From 5ffb1d3cfe174156a88528f6c2e23854f5363491 Mon Sep 17 00:00:00 2001 From: Alex Pott <alex.a.pott@googlemail.com> Date: Fri, 11 Jul 2014 13:04:53 +0100 Subject: [PATCH] Issue #2216535 by jhodgdon, Berdir: Replace Node overview topic and Node API topic with Entity Hooks topic. --- .../Config/Entity/ConfigEntityStorage.php | 2 + .../Entity/ContentEntityDatabaseStorage.php | 12 +- .../Core/Entity/EntityStorageInterface.php | 2 + .../Entity/EntityViewBuilderInterface.php | 2 + core/modules/block/block.api.php | 4 + core/modules/block/block.module | 4 +- core/modules/book/book.module | 14 +- core/modules/comment/comment.api.php | 166 ----- core/modules/comment/comment.module | 6 +- core/modules/field/field.api.php | 2 + core/modules/file/file.api.php | 128 +--- core/modules/file/file.module | 6 +- .../file/tests/file_test/file_test.module | 8 +- core/modules/forum/forum.module | 16 +- core/modules/history/history.module | 6 +- core/modules/image/image.module | 2 +- core/modules/language/language.module | 2 +- core/modules/menu_link/menu_link.api.php | 125 +--- core/modules/menu_ui/menu_ui.api.php | 76 --- core/modules/menu_ui/menu_ui.module | 27 +- core/modules/node/node.api.php | 428 +----------- core/modules/node/node.module | 16 +- .../node/src/Tests/NodeCreationTest.php | 3 +- .../src/Tests/NodeEntityViewModeAlterTest.php | 2 +- core/modules/node/src/Tests/NodeSaveTest.php | 12 +- .../node_access_test/node_access_test.module | 8 +- .../tests/modules/node_test/node_test.module | 10 +- .../node_test_exception.module | 2 +- core/modules/rdf/rdf.module | 2 +- core/modules/statistics/statistics.module | 4 +- core/modules/system/core.api.php | 95 ++- core/modules/system/entity.api.php | 636 +++++++++++++++++- .../src/Tests/Entity/EntityCrudHookTest.php | 14 +- core/modules/system/system.module | 2 +- .../entity_crud_hook_test.module | 98 +-- .../tests/modules/menu_test/menu_test.module | 6 +- core/modules/taxonomy/taxonomy.api.php | 310 --------- core/modules/taxonomy/taxonomy.module | 8 +- core/modules/toolbar/toolbar.module | 6 +- core/modules/tour/tour.api.php | 54 +- core/modules/tour/tour.module | 4 +- core/modules/tracker/tracker.module | 12 +- core/modules/user/user.api.php | 298 +------- core/modules/user/user.module | 20 +- 44 files changed, 884 insertions(+), 1776 deletions(-) delete mode 100644 core/modules/menu_ui/menu_ui.api.php delete mode 100644 core/modules/taxonomy/taxonomy.api.php diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php index 57e4243d1b20..d0148904f18a 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php @@ -35,6 +35,8 @@ * 'article'. Entity IDs may contain dots/periods. The entire remaining string * after the config_prefix in a config name forms the entity ID. Additional or * custom suffixes are not possible. + * + * @ingroup entity_api */ class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStorageInterface, ImportableEntityStorageInterface { diff --git a/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php b/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php index 2e2985710bcb..6f246f78ce1f 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityDatabaseStorage.php @@ -34,6 +34,8 @@ * the defined base fields. Entity types can override * ContentEntityDatabaseStorage::getSchema() to customize the generated * schema; e.g., to add additional indexes. + * + * @ingroup entity_api */ class ContentEntityDatabaseStorage extends ContentEntityStorageBase implements SqlEntityStorageInterface { @@ -350,15 +352,7 @@ protected function doLoadMultiple(array $ids = NULL) { } /** - * Maps from storage records to entity objects. - * - * This will attach fields, if the entity is fieldable. It calls - * hook_entity_load() for modules which need to add data to all entities. - * It also calls hook_TYPE_load() on the loaded entities. For example - * hook_node_load() or hook_user_load(). If your hook_TYPE_load() - * expects special parameters apart from the queried entities, you can set - * $this->hookLoadArguments prior to calling the method. - * See Drupal\node\NodeStorage::attachLoad() for an example. + * Maps from storage records to entity objects, and attaches fields. * * @param array $records * Associative array of query results, keyed on the entity ID. diff --git a/core/lib/Drupal/Core/Entity/EntityStorageInterface.php b/core/lib/Drupal/Core/Entity/EntityStorageInterface.php index e91f04c54f76..bb086e67336b 100644 --- a/core/lib/Drupal/Core/Entity/EntityStorageInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityStorageInterface.php @@ -17,6 +17,8 @@ * Most simple, SQL-based entity controllers will do better by extending * Drupal\Core\Entity\ContentEntityDatabaseStorage instead of implementing this * interface directly. + * + * @ingroup entity_api */ interface EntityStorageInterface { diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php b/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php index 32067a44de4f..89812fbef1ae 100644 --- a/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php @@ -12,6 +12,8 @@ /** * Defines a common interface for entity view controller classes. + * + * @ingroup entity_api */ interface EntityViewBuilderInterface { diff --git a/core/modules/block/block.api.php b/core/modules/block/block.api.php index a0f79bffe722..f43d984f4cde 100644 --- a/core/modules/block/block.api.php +++ b/core/modules/block/block.api.php @@ -85,6 +85,8 @@ * The block plugin instance. * * @see hook_block_view_BASE_BLOCK_ID_alter() + * @see entity_crud + * * @ingroup block_api */ function hook_block_view_alter(array &$build, \Drupal\block\BlockPluginInterface $block) { @@ -113,6 +115,8 @@ function hook_block_view_alter(array &$build, \Drupal\block\BlockPluginInterface * The block plugin instance. * * @see hook_block_view_alter() + * @see entity_crud + * * @ingroup block_api */ function hook_block_view_BASE_BLOCK_ID_alter(array &$build, \Drupal\block\BlockPluginInterface $block) { diff --git a/core/modules/block/block.module b/core/modules/block/block.module index 4681b8a550b4..9a4118d82eee 100644 --- a/core/modules/block/block.module +++ b/core/modules/block/block.module @@ -298,7 +298,7 @@ function template_preprocess_block(&$variables) { } /** - * Implements hook_user_role_delete(). + * Implements hook_ENTITY_TYPE_delete() for user_role entities. * * Removes deleted role from blocks that use it. */ @@ -315,7 +315,7 @@ function block_user_role_delete($role) { } /** - * Implements hook_menu_delete(). + * Implements hook_ENTITY_TYPE_delete() for menu entities. */ function block_menu_delete(Menu $menu) { if (!$menu->isSyncing()) { diff --git a/core/modules/book/book.module b/core/modules/book/book.module index 54aad063e3b8..ba00049b52a1 100644 --- a/core/modules/book/book.module +++ b/core/modules/book/book.module @@ -234,7 +234,7 @@ function book_form_update($form, $form_state) { } /** - * Implements hook_node_load(). + * Implements hook_ENTITY_TYPE_load() for node entities. */ function book_node_load($nodes) { /** @var \Drupal\book\BookManagerInterface $book_manager */ @@ -248,7 +248,7 @@ function book_node_load($nodes) { } /** - * Implements hook_node_view(). + * Implements hook_ENTITY_TYPE_view() for node entities. */ function book_node_view(array &$build, EntityInterface $node, EntityViewDisplayInterface $display, $view_mode) { if ($view_mode == 'full') { @@ -268,7 +268,7 @@ function book_node_view(array &$build, EntityInterface $node, EntityViewDisplayI } /** - * Implements hook_node_presave(). + * Implements hook_ENTITY_TYPE_presave() for node entities. */ function book_node_presave(EntityInterface $node) { // Make sure a new node gets a new menu link. @@ -278,7 +278,7 @@ function book_node_presave(EntityInterface $node) { } /** - * Implements hook_node_insert(). + * Implements hook_ENTITY_TYPE_insert() for node entities. */ function book_node_insert(EntityInterface $node) { /** @var \Drupal\book\BookManagerInterface $book_manager */ @@ -287,7 +287,7 @@ function book_node_insert(EntityInterface $node) { } /** - * Implements hook_node_update(). + * Implements hook_ENTITY_TYPE_update() for node entities. */ function book_node_update(EntityInterface $node) { /** @var \Drupal\book\BookManagerInterface $book_manager */ @@ -296,7 +296,7 @@ function book_node_update(EntityInterface $node) { } /** - * Implements hook_node_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for node entities. */ function book_node_predelete(EntityInterface $node) { if (!empty($node->book['bid'])) { @@ -555,7 +555,7 @@ function book_type_is_allowed($type) { } /** - * Implements hook_node_type_update(). + * Implements hook_ENTITY_TYPE_update() for node_type entities. * * Updates book.settings configuration object if the machine-readable name of a * node type is changed. diff --git a/core/modules/comment/comment.api.php b/core/modules/comment/comment.api.php index 176813b454cc..5430ee9f4acd 100644 --- a/core/modules/comment/comment.api.php +++ b/core/modules/comment/comment.api.php @@ -13,172 +13,6 @@ * @{ */ -/** - * Act on a comment being inserted or updated. - * - * This hook is invoked from $comment->save() before the comment is saved to the - * database. - * - * @param \Drupal\comment\Comment $comment - * The comment object. - */ -function hook_comment_presave(Drupal\comment\Comment $comment) { - // Remove leading & trailing spaces from the comment subject. - $comment->setSubject(trim($comment->getSubject())); -} - -/** - * Respond to creation of a new comment. - * - * @param \Drupal\comment\Comment $comment - * The comment object. - */ -function hook_comment_insert(Drupal\comment\Comment $comment) { - // Reindex the node when comments are added. - if ($comment->getCommentedEntityTypeId() == 'node') { - node_reindex_node_search($comment->getCommentedEntityId()); - } -} - -/** - * Respond to updates to a comment. - * - * @param \Drupal\comment\Comment $comment - * The comment object. - */ -function hook_comment_update(Drupal\comment\Comment $comment) { - // Reindex the node when comments are updated. - if ($comment->getCommentedEntityTypeId() == 'node') { - node_reindex_node_search($comment->getCommentedEntityId()); - } -} - -/** - * Act on a newly created comment. - * - * This hook runs after a new comment object has just been instantiated. It can - * be used to set initial values, e.g. to provide defaults. - * - * @param \Drupal\comment\Entity\Comment $comment - * The comment object. - */ -function hook_comment_create(\Drupal\comment\Entity\Comment $comment) { - if (!isset($comment->foo)) { - $comment->foo = 'some_initial_value'; - } -} - -/** - * Act on comments being loaded from the database. - * - * @param array $comments - * An array of comment objects indexed by cid. - */ -function hook_comment_load(Drupal\comment\Comment $comments) { - $result = db_query('SELECT cid, foo FROM {mytable} WHERE cid IN (:cids)', array(':cids' => array_keys($comments))); - foreach ($result as $record) { - $comments[$record->cid]->foo = $record->foo; - } -} - -/** - * Act on a comment that is being assembled before rendering. - * - * @param array &$build - * A renderable array representing the comment content. - * @param \Drupal\comment\Entity\Comment $comment $comment - * Passes in the comment the action is being performed on. - * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display - * The entity view display holding the display options configured for the - * comment components. - * @param $view_mode - * View mode, e.g. 'full', 'teaser'... - * @param $langcode - * The language code used for rendering. - * - * @see hook_entity_view() - */ -function hook_comment_view(array &$build, \Drupal\comment\Entity\Comment $comment, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode, $langcode) { - // Only do the extra work if the component is configured to be displayed. - // This assumes a 'mymodule_addition' extra field has been defined for the - // node type in hook_entity_extra_field_info(). - if ($display->getComponent('mymodule_addition')) { - $build['mymodule_addition'] = array( - '#markup' => mymodule_addition($comment), - '#theme' => 'mymodule_my_additional_field', - ); - } -} - -/** - * Alter the results of comment_view(). - * - * This hook is called after the content has been assembled in a structured - * array and may be used for doing processing which requires that the complete - * comment content structure has been built. - * - * If the module wishes to act on the rendered HTML of the comment rather than - * the structured content array, it may use this hook to add a #post_render - * callback. Alternatively, it could also implement hook_preprocess_HOOK() for - * comment.html.twig. See drupal_render() documentation for details. - * - * @param array &$build - * A renderable array representing the comment. - * @param \Drupal\comment\Entity\Comment $comment - * The comment being rendered. - * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display - * The entity view display holding the display options configured for the - * comment components. - * - * @see comment_view() - * @see hook_entity_view_alter() - */ -function hook_comment_view_alter(array &$build, \Drupal\comment\Entity\Comment $comment, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) { - // Check for the existence of a field added by another module. - if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) { - // Change its weight. - $build['an_additional_field']['#weight'] = -10; - } - - // Add a #post_render callback to act on the rendered HTML of the comment. - $build['#post_render'][] = 'my_module_comment_post_render'; -} - -/** - * Act before comment deletion. - * - * This hook is invoked from entity_delete_multiple() before field values are - * deleted and before the comment is actually removed from the database. - * - * @param \Drupal\comment\Comment $comment - * The comment object for the comment that is about to be deleted. - * - * @see hook_comment_delete() - * @see entity_delete_multiple() - */ -function hook_comment_predelete(Drupal\comment\Comment $comment) { - // Delete a record associated with the comment in a custom table. - db_delete('example_comment_table') - ->condition('cid', $comment->id()) - ->execute(); -} - -/** - * Respond to comment deletion. - * - * This hook is invoked from entity_delete_multiple() after field values are - * deleted and after the comment has been removed from the database. - * - * @param \Drupal\comment\Comment $comment - * The comment object for the comment that has been deleted. - * - * @see hook_comment_predelete() - * @see entity_delete_multiple() - */ -function hook_comment_delete(Drupal\comment\Comment $comment) { - drupal_set_message(t('Comment: @subject has been deleted', array('@subject' => $comment->getSubject()))); -} - /** * Alter the links of a comment. * diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index f567e88ceb06..401a3cf99b38 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -434,7 +434,7 @@ function comment_node_links_alter(array &$node_links, NodeInterface $node, array } /** - * Implements hook_node_view_alter(). + * Implements hook_ENTITY_TYPE_view_alter() for node entities. */ function comment_node_view_alter(array &$build, EntityInterface $node, EntityViewDisplayInterface $display) { if (\Drupal::moduleHandler()->moduleExists('history')) { @@ -639,7 +639,7 @@ function comment_view_multiple($comments, $view_mode = 'full', $langcode = NULL) } /** - * Implements hook_form_FORM_ID_alter(). + * Implements hook_form_FORM_ID_alter() for field_ui_field_overview_form. */ function comment_form_field_ui_field_overview_form_alter(&$form, $form_state) { $request = \Drupal::request(); @@ -886,7 +886,7 @@ function comment_user_cancel($edit, $account, $method) { } /** - * Implements hook_user_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for user entities. */ function comment_user_predelete($account) { $entity_query = \Drupal::entityQuery('comment'); diff --git a/core/modules/field/field.api.php b/core/modules/field/field.api.php index f364c517d237..fed48ca1065d 100644 --- a/core/modules/field/field.api.php +++ b/core/modules/field/field.api.php @@ -253,6 +253,8 @@ function hook_field_info_max_weight($entity_type, $bundle, $context, $context_mo * The field as it will be post-update. * @param \Drupal\field\FieldConfigInterface $prior_field * The field as it is pre-update. + * + * @see entity_crud */ function hook_field_config_update_forbid(\Drupal\field\FieldConfigInterface $field, \Drupal\field\FieldConfigInterface $prior_field) { // A 'list' field stores integer keys mapped to display values. If diff --git a/core/modules/file/file.api.php b/core/modules/file/file.api.php index 898caa5d3cb0..6ec14c5590be 100644 --- a/core/modules/file/file.api.php +++ b/core/modules/file/file.api.php @@ -5,43 +5,10 @@ * Hooks for file module. */ - /** - * Act on a newly created file. - * - * This hook runs after a new file object has just been instantiated. It can be - * used to set initial values, e.g. to provide defaults. - * - * @param \Drupal\file\Entity\File $file - * The file object. + * @addtogroup hooks + * @{ */ -function hook_file_create(\Drupal\file\Entity\File $file) { - if (!isset($file->foo)) { - $file->foo = 'some_initial_value'; - } -} - -/** - * Load additional information into file entities. - * - * file_load_multiple() calls this hook to allow modules to load - * additional information into each file. - * - * @param $files - * An array of file entities, indexed by fid. - * - * @see file_load_multiple() - * @see file_load() - */ -function hook_file_load($files) { - // Add the upload specific data into the file entity. - $result = db_query('SELECT * FROM {upload} u WHERE u.fid IN (:fids)', array(':fids' => array_keys($files)))->fetchAll(PDO::FETCH_ASSOC); - foreach ($result as $record) { - foreach ($record as $key => $value) { - $files[$record['target_id']]->$key = $value; - } - } -} /** * Check that files meet a given criteria. @@ -70,58 +37,6 @@ function hook_file_validate(Drupal\file\FileInterface $file) { return $errors; } -/** - * Act on a file being inserted or updated. - * - * This hook is called when a file has been added to the database. The hook - * doesn't distinguish between files created as a result of a copy or those - * created by an upload. - * - * @param \Drupal\file\FileInterface $file - * The file entity that is about to be created or updated. - */ -function hook_file_presave(Drupal\file\FileInterface $file) { - // Change the owner of the file. - $file->uid->value = 1; -} - -/** - * Respond to a file being added. - * - * This hook is called after a file has been added to the database. The hook - * doesn't distinguish between files created as a result of a copy or those - * created by an upload. - * - * @param \Drupal\file\FileInterface $file - * The file that has been added. - */ -function hook_file_insert(Drupal\file\FileInterface $file) { - // Add a message to the log, if the file is a jpg - $validate = file_validate_extensions($file, 'jpg'); - if (empty($validate)) { - \Drupal::logger('file')->notice('A jpg has been added.'); - } -} - -/** - * Respond to a file being updated. - * - * This hook is called when an existing file is saved. - * - * @param \Drupal\file\FileInterface $file - * The file that has just been updated. - */ -function hook_file_update(Drupal\file\FileInterface $file) { - // Make sure that the file name starts with the owner's user name. - if (strpos($file->getFilename(), $file->getOwner()->name) !== 0) { - $old_filename = $file->getFilename(); - $file->setFilename($file->getOwner()->name . '_' . $file->getFilename()); - $file->save(); - - \Drupal::logger('file')->notice('%source has been renamed to %destination', array('%source' => $old_filename, '%destination' => $file->getFilename())); - } -} - /** * Respond to a file that has been copied. * @@ -162,41 +77,6 @@ function hook_file_move(Drupal\file\FileInterface $file, Drupal\file\FileInterfa } } -/** - * Act prior to file deletion. - * - * This hook is invoked when deleting a file before the file is removed from the - * filesystem and before its records are removed from the database. - * - * @param \Drupal\file\FileInterface $file - * The file that is about to be deleted. - * - * @see hook_file_delete() - * @see \Drupal\file\FileStorage::delete() - * @see upload_file_delete() - */ -function hook_file_predelete(Drupal\file\FileInterface $file) { - // Delete all information associated with the file. - db_delete('upload')->condition('fid', $file->id())->execute(); -} - -/** - * Respond to file deletion. - * - * This hook is invoked after the file has been removed from - * the filesystem and after its records have been removed from the database. - * - * @param \Drupal\file\FileInterface $file - * The file that has just been deleted. - * - * @see hook_file_predelete() - * @see \Drupal\file\FileStorage::delete() - */ -function hook_file_delete(Drupal\file\FileInterface $file) { - // Delete all information associated with the file. - db_delete('upload')->condition('fid', $file->id())->execute(); -} - /** * Control download access to files. * @@ -251,3 +131,7 @@ function hook_file_download_access_alter(&$grants, $context) { $grants = array('node' => $grants['node']); } } + +/** + * @} End of "addtogroup hooks". + */ diff --git a/core/modules/file/file.module b/core/modules/file/file.module index 760a5832a57b..e78c6d642fb6 100644 --- a/core/modules/file/file.module +++ b/core/modules/file/file.module @@ -87,7 +87,7 @@ function file_element_info() { * @deprecated in Drupal 8.x, will be removed before Drupal 9.0. * Use \Drupal\file\Entity\File::loadMultiple(). * - * @see hook_file_load() + * @see hook_ENTITY_TYPE_load() * @see file_load() * @see entity_load() * @see \Drupal\Core\Entity\Query\EntityQueryInterface @@ -113,7 +113,7 @@ function file_load_multiple(array $fids = NULL, $reset = FALSE) { * @deprecated in Drupal 8.x, will be removed before Drupal 9.0. * Use \Drupal\file\Entity\File::load(). * - * @see hook_file_load() + * @see hook_ENTITY_TYPE_load() * @see file_load_multiple() */ function file_load($fid, $reset = FALSE) { @@ -1002,7 +1002,7 @@ function file_progress_implementation() { } /** - * Implements hook_file_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for file entities. */ function file_file_predelete(File $file) { // TODO: Remove references to a file that is in-use. diff --git a/core/modules/file/tests/file_test/file_test.module b/core/modules/file/tests/file_test/file_test.module index 5fcd15fd9157..b1bdeb3cf33a 100644 --- a/core/modules/file/tests/file_test/file_test.module +++ b/core/modules/file/tests/file_test/file_test.module @@ -150,7 +150,7 @@ function file_test_set_return($op, $value) { } /** - * Implements hook_file_load(). + * Implements hook_ENTITY_TYPE_load() for file entities. */ function file_test_file_load($files) { foreach ($files as $file) { @@ -178,14 +178,14 @@ function file_test_file_download($uri) { } /** - * Implements hook_file_insert(). + * Implements hook_ENTITY_TYPE_insert() for file entities. */ function file_test_file_insert(File $file) { _file_test_log_call('insert', array($file->id())); } /** - * Implements hook_file_update(). + * Implements hook_ENTITY_TYPE_update() for file entities. */ function file_test_file_update(File $file) { _file_test_log_call('update', array($file->id())); @@ -206,7 +206,7 @@ function file_test_file_move(File $file, File $source) { } /** - * Implements hook_file_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for file entities. */ function file_test_file_predelete(File $file) { _file_test_log_call('delete', array($file->id())); diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module index be7ef15b8199..23293fe2ea6b 100644 --- a/core/modules/forum/forum.module +++ b/core/modules/forum/forum.module @@ -233,7 +233,7 @@ function forum_node_validate(EntityInterface $node, $form, &$form_state) { } /** - * Implements hook_node_presave(). + * Implements hook_ENTITY_TYPE_presave() for node entities. * * Assigns the forum taxonomy when adding a topic from within a forum. */ @@ -256,7 +256,7 @@ function forum_node_presave(EntityInterface $node) { } /** - * Implements hook_node_update(). + * Implements hook_ENTITY_TYPE_update() for node entities. */ function forum_node_update(EntityInterface $node) { if (\Drupal::service('forum_manager')->checkNodeType($node)) { @@ -298,7 +298,7 @@ function forum_node_update(EntityInterface $node) { } /** - * Implements hook_node_insert(). + * Implements hook_ENTITY_TYPE_insert() for node entities. */ function forum_node_insert(EntityInterface $node) { if (\Drupal::service('forum_manager')->checkNodeType($node)) { @@ -316,7 +316,7 @@ function forum_node_insert(EntityInterface $node) { } /** - * Implements hook_node_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for node entities. */ function forum_node_predelete(EntityInterface $node) { if (\Drupal::service('forum_manager')->checkNodeType($node)) { @@ -328,7 +328,7 @@ function forum_node_predelete(EntityInterface $node) { } /** - * Implements hook_node_load(). + * Implements hook_ENTITY_TYPE_load() for node entities. */ function forum_node_load($nodes) { $node_vids = array(); @@ -358,7 +358,7 @@ function forum_permission() { } /** - * Implements hook_comment_update(). + * Implements hook_ENTITY_TYPE_update() for comment entities. */ function forum_comment_update(CommentInterface $comment) { if ($comment->getCommentedEntityTypeId() == 'node') { @@ -367,7 +367,7 @@ function forum_comment_update(CommentInterface $comment) { } /** - * Implements hook_comment_insert(). + * Implements hook_ENTITY_TYPE_insert() for comment entities. */ function forum_comment_insert(CommentInterface $comment) { if ($comment->getCommentedEntityTypeId() == 'node') { @@ -376,7 +376,7 @@ function forum_comment_insert(CommentInterface $comment) { } /** - * Implements hook_comment_delete(). + * Implements hook_ENTITY_TYPE_delete() for comment entities. */ function forum_comment_delete(CommentInterface $comment) { if ($comment->getCommentedEntityTypeId() == 'node') { diff --git a/core/modules/history/history.module b/core/modules/history/history.module index 06e82d89e03f..f4c9742926b4 100644 --- a/core/modules/history/history.module +++ b/core/modules/history/history.module @@ -130,7 +130,7 @@ function history_cron() { } /** - * Implements hook_node_view_alter(). + * Implements hook_ENTITY_TYPE_view_alter() for node entities. */ function history_node_view_alter(array &$build, EntityInterface $node, EntityViewDisplayInterface $display) { // Update the history table, stating that this user viewed this node. @@ -148,7 +148,7 @@ function history_node_view_alter(array &$build, EntityInterface $node, EntityVie } /** - * Implements hook_node_delete(). + * Implements hook_ENTITY_TYPE_delete() for node entities. */ function history_node_delete(EntityInterface $node) { db_delete('history') @@ -170,7 +170,7 @@ function history_user_cancel($edit, $account, $method) { } /** - * Implements hook_user_delete(). + * Implements hook_ENTITY_TYPE_delete() for user entities. */ function history_user_delete($account) { db_delete('history') diff --git a/core/modules/image/image.module b/core/modules/image/image.module index 406423628734..2ff2ecb7b143 100644 --- a/core/modules/image/image.module +++ b/core/modules/image/image.module @@ -228,7 +228,7 @@ function image_file_move(File $file, File $source) { } /** - * Implements hook_file_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for file entities. */ function image_file_predelete(File $file) { // Delete any image derivatives of this image. diff --git a/core/modules/language/language.module b/core/modules/language/language.module index e23d73f4c639..5ac331bf1c3e 100644 --- a/core/modules/language/language.module +++ b/core/modules/language/language.module @@ -347,7 +347,7 @@ function language_get_default_configuration_settings_key($entity_type, $bundle) } /** - * Implements hook_node_type_update(). + * Implements hook_ENTITY_TYPE_update() for node_type entities. */ function language_node_type_update(NodeTypeInterface $type) { if ($type->original->id() != $type->id()) { diff --git a/core/modules/menu_link/menu_link.api.php b/core/modules/menu_link/menu_link.api.php index b4e88928b576..470243671874 100644 --- a/core/modules/menu_link/menu_link.api.php +++ b/core/modules/menu_link/menu_link.api.php @@ -17,7 +17,7 @@ * translated; i.e., after the user access to the link's target page has * been checked. It is only invoked if $menu_link['options']['alter'] has been * set to a non-empty value (e.g. TRUE). This flag should be set using - * hook_menu_link_presave(). + * hook_ENTITY_TYPE_presave() for entity 'menu_link'. * * Implementations of this hook are able to alter any property of the menu link. * For example, this hook may be used to add a page-specific query string to all @@ -37,129 +37,6 @@ function hook_translated_menu_link_alter(\Drupal\menu_link\Entity\MenuLink &$men } } -/** - * Alter menu links when loaded and before they are rendered. - * - * This hook is only invoked if $menu_link->options['alter'] has been set to a - * non-empty value (e.g., TRUE). This flag should be set using - * hook_menu_link_presave(). - * @ todo The paragraph above is lying! This hasn't been (re)implemented yet. - * - * Implementations of this hook are able to alter any property of the menu link. - * For example, this hook may be used to add a page-specific query string to all - * menu links, or hide a certain link by setting: - * @code - * 'hidden' => 1, - * @endcode - * - * @param array $menu_links - * An array of menu link entities. - * - * @see hook_menu_link_presave() - */ -function hook_menu_link_load($menu_links) { - foreach ($menu_links as $menu_link) { - if ($menu_link->href == 'devel/cache/clear') { - $menu_link->options['query'] = drupal_get_destination(); - } - } -} - - -/** - * Alter the data of a menu link entity before it is created or updated. - * - * @param \Drupal\menu_link\Entity\MenuLink $menu_link - * A menu link entity. - * - * @see hook_menu_link_load() - */ -function hook_menu_link_presave(\Drupal\menu_link\Entity\MenuLink $menu_link) { - // Make all new admin links hidden (a.k.a disabled). - if (strpos($menu_link->link_path, 'admin') === 0 && $menu_link->isNew()) { - $menu_link->hidden = 1; - } - // Flag a link to be altered by hook_menu_link_load(). - if ($menu_link->link_path == 'devel/cache/clear') { - $menu_link->options['alter'] = TRUE; - } - // Flag a menu link to be altered by hook_menu_link_load(), but only if it is - // derived from a menu router item; i.e., do not alter a custom menu link - // pointing to the same path that has been created by a user. - if ($menu_link->machine_name == 'user.page') { - $menu_link->options['alter'] = TRUE; - } -} - -/** - * Inform modules that a menu link has been created. - * - * This hook is used to notify modules that menu links have been - * created. Contributed modules may use the information to perform - * actions based on the information entered into the menu system. - * - * @param \Drupal\menu_link\Entity\MenuLink $menu_link - * A menu link entity. - * - * @see hook_menu_link_presave() - * @see hook_menu_link_update() - * @see hook_menu_link_delete() - */ -function hook_menu_link_insert(\Drupal\menu_link\Entity\MenuLink $menu_link) { - // In our sample case, we track menu items as editing sections - // of the site. These are stored in our table as 'disabled' items. - $record['mlid'] = $menu_link->id(); - $record['menu_name'] = $menu_link->menu_name; - $record['status'] = 0; - db_insert('menu_example')->fields($record)->execute(); -} - -/** - * Inform modules that a menu link has been updated. - * - * This hook is used to notify modules that menu items have been - * updated. Contributed modules may use the information to perform - * actions based on the information entered into the menu system. - * - * @param \Drupal\menu_link\Entity\MenuLink $menu_link - * A menu link entity. - * - * @see hook_menu_link_presave() - * @see hook_menu_link_insert() - * @see hook_menu_link_delete() - */ -function hook_menu_link_update(\Drupal\menu_link\Entity\MenuLink $menu_link) { - // If the parent menu has changed, update our record. - $menu_name = db_query("SELECT menu_name FROM {menu_example} WHERE mlid = :mlid", array(':mlid' => $menu_link->id()))->fetchField(); - if ($menu_name != $menu_link->menu_name) { - db_update('menu_example') - ->fields(array('menu_name' => $menu_link->menu_name)) - ->condition('mlid', $menu_link->id()) - ->execute(); - } -} - -/** - * Inform modules that a menu link has been deleted. - * - * This hook is used to notify modules that menu links have been - * deleted. Contributed modules may use the information to perform - * actions based on the information entered into the menu system. - * - * @param \Drupal\menu_link\Entity\MenuLink $menu_link - * A menu link entity. - * - * @see hook_menu_link_presave() - * @see hook_menu_link_insert() - * @see hook_menu_link_update() - */ -function hook_menu_link_delete(\Drupal\menu_link\Entity\MenuLink $menu_link) { - // Delete the record from our table. - db_delete('menu_example') - ->condition('mlid', $menu_link->id()) - ->execute(); -} - /** * @} End of "addtogroup hooks". */ diff --git a/core/modules/menu_ui/menu_ui.api.php b/core/modules/menu_ui/menu_ui.api.php deleted file mode 100644 index 04277153e167..000000000000 --- a/core/modules/menu_ui/menu_ui.api.php +++ /dev/null @@ -1,76 +0,0 @@ -<?php - -/** - * @file - * Hooks provided by the Menu UI module. - */ - -/** - * @addtogroup hooks - * @{ - */ - -/** - * Respond to a custom menu creation. - * - * This hook is used to notify modules that a custom menu has been created. - * Contributed modules may use the information to perform actions based on the - * information entered into the menu system. - * - * @param \Drupal\system\MenuInterface $menu - * The menu entity that was created. - * - * @see hook_menu_update() - * @see hook_menu_delete() - */ -function hook_menu_insert(\Drupal\system\MenuInterface $menu) { - drupal_set_message(t('You have just created a menu with a machine name %id.', array( - '%id' => $menu->id(), - ))); -} - -/** - * Respond to a custom menu update. - * - * This hook is used to notify modules that a custom menu has been updated. - * Contributed modules may use the information to perform actions based on the - * information entered into the menu system. - * - * @param \Drupal\system\MenuInterface $menu - * The menu entity that was updated. - * - * @see hook_menu_insert() - * @see hook_menu_delete() - */ -function hook_menu_update(\Drupal\system\MenuInterface $menu) { - if ($type->original->id() != $type->id()) { - drupal_set_message(t('You have just changed the machine name of the menu %old_id to %id.', array( - '%old_id' => $menu->original->id(), - '%id' => $menu->id(), - ))); - } -} - -/** - * Respond to a custom menu deletion. - * - * This hook is used to notify modules that a custom menu along with all links - * contained in it (if any) has been deleted. Contributed modules may use the - * information to perform actions based on the information entered into the menu - * system. - * - * @param \Drupal\system\MenuInterface $menu - * The menu entity that was deleted. - * - * @see hook_menu_insert() - * @see hook_menu_update() - */ -function hook_menu_delete(\Drupal\system\MenuInterface $menu) { - drupal_set_message(t('You have just deleted the menu with machine name %id.', array( - '%id' => $menu->id(), - ))); -} - -/** - * @} End of "addtogroup hooks". - */ diff --git a/core/modules/menu_ui/menu_ui.module b/core/modules/menu_ui/menu_ui.module index 5e2f5bcf6e14..70b5b5944e54 100644 --- a/core/modules/menu_ui/menu_ui.module +++ b/core/modules/menu_ui/menu_ui.module @@ -5,10 +5,7 @@ * Allows administrators to customize the site's navigation menus. * * A menu (in this context) is a hierarchical collection of links, generally - * used for navigation. This is not to be confused with the - * @link menu Menu system @endlink of menu.inc and hook_menu(), which defines - * page routing requests for Drupal, and also allows the defined page routing - * URLs to be added to the main site navigation menu. + * used for navigation. */ use Drupal\Core\Entity\EntityInterface; @@ -114,7 +111,7 @@ function menu_ui_theme() { } /** - * Implements hook_menu_insert() + * Implements hook_ENTITY_TYPE_insert( for menu entities. */ function menu_ui_menu_insert(Menu $menu) { menu_cache_clear_all(); @@ -142,7 +139,7 @@ function menu_ui_menu_insert(Menu $menu) { } /** - * Implements hook_menu_update(). + * Implements hook_ENTITY_TYPE_update() for menu entities. */ function menu_ui_menu_update(Menu $menu) { menu_cache_clear_all(); @@ -153,7 +150,7 @@ function menu_ui_menu_update(Menu $menu) { } /** - * Implements hook_menu_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for menu entities. */ function menu_ui_menu_predelete(Menu $menu) { // Delete all links from the menu. @@ -174,7 +171,7 @@ function menu_ui_menu_predelete(Menu $menu) { } /** - * Implements hook_menu_delete(). + * Implements hook_ENTITY_TYPE_delete() for menu entities. */ function menu_ui_menu_delete(Menu $menu) { menu_cache_clear_all(); @@ -297,21 +294,21 @@ function menu_ui_block_view_system_menu_block_alter(array &$build, BlockPluginIn } /** - * Implements hook_node_insert(). + * Implements hook_ENTITY_TYPE_insert() for node entities. */ function menu_ui_node_insert(EntityInterface $node) { menu_ui_node_save($node); } /** - * Implements hook_node_update(). + * Implements hook_ENTITY_TYPE_update() for node entities. */ function menu_ui_node_update(EntityInterface $node) { menu_ui_node_save($node); } /** - * Implements hook_node_type_insert(). + * Implements hook_ENTITY_TYPE_insert() for node_type entities. */ function menu_ui_node_type_insert(NodeTypeInterface $type) { if ($type->isSyncing()) { @@ -324,7 +321,7 @@ function menu_ui_node_type_insert(NodeTypeInterface $type) { } /** - * Implements hook_node_type_delete(). + * Implements hook_ENTITY_TYPE_delete() for node_type entities. */ function menu_ui_node_type_delete(NodeTypeInterface $type) { if ($type->isSyncing()) { @@ -334,7 +331,7 @@ function menu_ui_node_type_delete(NodeTypeInterface $type) { } /** - * Helper for hook_node_insert() and hook_node_update(). + * Helper for hook_ENTITY_TYPE_insert() and hook_ENTITY_TYPE_update() for nodes. */ function menu_ui_node_save(EntityInterface $node) { if (isset($node->menu)) { @@ -363,7 +360,7 @@ function menu_ui_node_save(EntityInterface $node) { } /** - * Implements hook_node_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for node entities. */ function menu_ui_node_predelete(EntityInterface $node) { // Delete all Menu UI module links that point to this node. @@ -442,7 +439,7 @@ function _menu_ui_parent_depth_limit($item) { } /** - * Implements hook_form_BASE_FORM_ID_alter(). + * Implements hook_form_BASE_FORM_ID_alter() for node_form. * * Adds menu item fields to the node form. * diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php index 35ac5332874f..247c239ca4ec 100644 --- a/core/modules/node/node.api.php +++ b/core/modules/node/node.api.php @@ -6,105 +6,7 @@ /** * @file - * Hooks provided by the Node module. - */ - -/** - * @defgroup node_api_hooks Node API Hooks - * @{ - * Functions to define and modify content types. - * - * Each content type is maintained by a primary module, which is either - * node.module (for content types created in the user interface) or the module - * that defines the content type by providing configuration file. - * - * During node operations (create, insert, update, view, delete, etc.), there - * are several sets of hooks that get invoked to allow modules to modify the - * base node operation: - * - All-module hooks: This set of hooks is invoked on all implementing modules, - * to allow other modules to modify what the primary node module is doing. For - * example, hook_node_insert() is invoked on all modules when creating a forum - * node. - * - Field hooks: Hooks related to the fields attached to the node. These are - * invoked from the field operations functions described below, and can be - * either field-type-specific or all-module hooks. - * - Entity hooks: Generic hooks for "entity" operations. These are always - * invoked on all modules. - * - * Here is a list of the node and entity hooks that are invoked, and other - * steps that take place during node operations: - * - Instantiating a new node: - * - hook_node_create() (all) - * - hook_entity_create() (all) - * - Creating a new node (calling $node->save() on a new node): - * - hook_node_presave() (all) - * - hook_entity_presave() (all) - * - Node and revision records are written to the database - * - hook_node_insert() (all) - * - hook_entity_insert() (all) - * - hook_node_access_records() (all) - * - hook_node_access_records_alter() (all) - * - Updating an existing node (calling $node->save() on an existing node): - * - hook_node_presave() (all) - * - hook_entity_presave() (all) - * - Node and revision records are written to the database - * - hook_node_update() (all) - * - hook_entity_update() (all) - * - hook_node_access_records() (all) - * - hook_node_access_records_alter() (all) - * - Loading a node (calling node_load(), node_load_multiple(), entity_load(), - * or entity_load_multiple() with $entity_type of 'node'): - * - Node and revision information is read from database. - * - hook_entity_load() (all) - * - hook_node_load() (all) - * - Viewing a single node (calling node_view() - note that the input to - * node_view() is a loaded node, so the Loading steps above are already done): - * - hook_entity_prepare_view() (all) - * - hook_entity_display_build_alter() (all) - * - hook_node_view() (all) - * - hook_entity_view() (all) - * - hook_node_view_alter() (all) - * - hook_entity_view_alter() (all) - * - Viewing multiple nodes (calling node_view_multiple() - note that the input - * to node_view_multiple() is a set of loaded nodes, so the Loading steps - * above are already done): - * - hook_entity_prepare_view() (all) - * - hook_entity_display_build_alter() (all) - * - hook_node_view() (all) - * - hook_entity_view() (all) - * - hook_node_view_alter() (all) - * - hook_entity_view_alter() (all) - * - Deleting a node (calling $node->delete() or entity_delete_multiple()): - * - Node is loaded (see Loading section above) - * - hook_node_predelete() (all) - * - hook_entity_predelete() (all) - * - Node and revision information are deleted from database - * - hook_node_delete() (all) - * - hook_entity_delete() (all) - * - Deleting a node revision (calling node_revision_delete()): - * - Node is loaded (see Loading section above) - * - Revision information is deleted from database - * - hook_node_revision_delete() (all) - * - Preparing a node for editing (calling node_form() - note that if it is an - * existing node, it will already be loaded; see the Loading section above): - * - hook_node_prepare_form() (all) - * - hook_entity_prepare_form() (all) - * - @todo hook for EntityFormDisplay::buildForm() - * - Validating a node during editing form submit (calling - * node_form_validate()): - * - hook_node_validate() (all) - * - Searching (using the 'node_search' plugin): - * - hook_ranking() (all) - * - Query is executed to find matching nodes - * - Resulting node is loaded (see Loading section above) - * - Resulting node is prepared for viewing (see Viewing a single node above) - * - comment_node_update_index() is called (this adds "N comments" text) - * - hook_node_search_result() (all) - * - Search indexing (calling updateIndex() on the 'node_search' plugin): - * - Node is loaded (see Loading section above) - * - Node is prepared for viewing (see Viewing a single node above) - * - hook_node_update_index() (all) - * @} + * Hooks specific to the Node module. */ /** @@ -380,147 +282,6 @@ function hook_node_grants_alter(&$grants, \Drupal\Core\Session\AccountInterface } } -/** - * Act before node deletion. - * - * This hook is invoked from entity_delete_multiple() before - * hook_entity_predelete() is called and field values are deleted, and before - * the node is removed from the node table in the database. - * - * @param \Drupal\node\NodeInterface $node - * The node that is about to be deleted. - * - * @see hook_node_predelete() - * @see entity_delete_multiple() - * @ingroup node_api_hooks - */ -function hook_node_predelete(\Drupal\node\NodeInterface $node) { - db_delete('mytable') - ->condition('nid', $node->id()) - ->execute(); -} - -/** - * Respond to node deletion. - * - * This hook is invoked from entity_delete_multiple() after field values are - * deleted and after the node has been removed from the database. - * - * @param \Drupal\node\NodeInterface $node - * The node that has been deleted. - * - * @see hook_node_predelete() - * @see entity_delete_multiple() - * @ingroup node_api_hooks - */ -function hook_node_delete(\Drupal\node\NodeInterface $node) { - drupal_set_message(t('Node: @title has been deleted', array('@title' => $node->label()))); -} - -/** - * Respond to deletion of a node revision. - * - * This hook is invoked from node_revision_delete() after the revision has been - * removed from the node_revision table, and before field values are deleted. - * - * @param \Drupal\node\NodeInterface $node - * The node revision (node object) that is being deleted. - * - * @ingroup node_api_hooks - */ -function hook_node_revision_delete(\Drupal\node\NodeInterface $node) { - db_delete('mytable') - ->condition('vid', $node->getRevisionId()) - ->execute(); -} - -/** - * Respond to creation of a new node. - * - * This hook is invoked from $node->save() after the database query that will - * insert the node into the node table is scheduled for execution, and after - * field values are saved. - * - * Note that when this hook is invoked, the changes have not yet been written to - * the database, because a database transaction is still in progress. The - * transaction is not finalized until the save operation is entirely completed - * and $node->save() goes out of scope. You should not rely on data in the - * database at this time as it is not updated yet. You should also note that any - * write/update database queries executed from this hook are also not committed - * immediately. Check $node->save() and db_transaction() for more info. - * - * @param \Drupal\node\NodeInterface $node - * The node that is being created. - * - * @ingroup node_api_hooks - */ -function hook_node_insert(\Drupal\node\NodeInterface $node) { - db_insert('mytable') - ->fields(array( - 'nid' => $node->id(), - 'extra' => $node->extra, - )) - ->execute(); -} - -/** - * Act on a newly created node. - * - * This hook runs after a new node object has just been instantiated. It can be - * used to set initial values, e.g. to provide defaults. - * - * @param \Drupal\node\NodeInterface $node - * The node object. - * - * @ingroup node_api_hooks - */ -function hook_node_create(\Drupal\node\NodeInterface $node) { - if (!isset($node->foo)) { - $node->foo = 'some_initial_value'; - } -} - -/** - * Act on arbitrary nodes being loaded from the database. - * - * This hook should be used to add information that is not in the node or node - * revisions table, not to replace information that is in these tables (which - * could interfere with the entity cache). For performance reasons, information - * for all available nodes should be loaded in a single query where possible. - * - * This hook is invoked during node loading, which is handled by entity_load(), - * via classes Drupal\node\NodeStorage and - * Drupal\Core\Entity\ContentEntityDatabaseStorage. After the node information - * and field values are read from the database or the entity cache, - * hook_entity_load() is invoked on all implementing modules, and finally - * hook_node_load() is invoked on all implementing modules. - * - * @param $nodes - * An array of the nodes being loaded, keyed by nid. - * - * For a detailed usage example, see nodeapi_example.module. - * - * @ingroup node_api_hooks - */ -function hook_node_load($nodes) { - // Decide whether any of $types are relevant to our purposes. - $types_we_want_to_process = \Drupal::config('my_types')->get('types'); - $nids = array(); - foreach ($nodes as $node) { - if (in_array($node->bundle(), $types_we_want_to_process)) { - $nids = $node->id(); - } - } - if ($nids) { - // Gather our extra data for each of these nodes. - $result = db_query('SELECT nid, foo FROM {mytable} WHERE nid IN(:nids)', array(':nids' => $nids)); - // Add our extra data to the node objects. - foreach ($result as $record) { - $nodes[$record->nid]->foo = $record->foo; - } - } -} - /** * Controls access to a node. * @@ -588,27 +349,6 @@ function hook_node_access(\Drupal\node\NodeInterface $node, $op, $account, $lang return NODE_ACCESS_IGNORE; } - -/** - * Act on a node object about to be shown on the add/edit form. - * - * This hook is invoked from NodeForm::prepareEntity(). - * - * @param \Drupal\node\NodeInterface $node - * The node that is about to be shown on the form. - * @param $operation - * The current operation. - * @param array $form_state - * An associative array containing the current state of the form. - * - * @ingroup node_api_hooks - */ -function hook_node_prepare_form(\Drupal\node\NodeInterface $node, $operation, array &$form_state) { - if (!isset($node->my_rating)) { - $node->my_rating = \Drupal::config("my_rating_{$node->bundle()}")->get('enabled'); - } -} - /** * Act on a node being displayed as a search result. * @@ -629,60 +369,13 @@ function hook_node_prepare_form(\Drupal\node\NodeInterface $node, $operation, ar * @see template_preprocess_search_result() * @see search-result.html.twig * - * @ingroup node_api_hooks + * @ingroup entity_crud */ function hook_node_search_result(\Drupal\node\NodeInterface $node, $langcode) { $rating = db_query('SELECT SUM(points) FROM {my_rating} WHERE nid = :nid', array('nid' => $node->id()))->fetchField(); return array('rating' => format_plural($rating, '1 point', '@count points')); } -/** - * Act on a node being inserted or updated. - * - * This hook is invoked from $node->save() before the node is saved to the - * database. - * - * @param \Drupal\node\NodeInterface $node - * The node that is being inserted or updated. - * - * @ingroup node_api_hooks - */ -function hook_node_presave(\Drupal\node\NodeInterface $node) { - if ($node->id() && $node->moderate) { - // Reset votes when node is updated: - $node->score = 0; - $node->users = ''; - $node->votes = 0; - } -} - -/** - * Respond to updates to a node. - * - * This hook is invoked from $node->save() after the database query that will - * update node in the node table is scheduled for execution, and after field - * values are saved. - * - * Note that when this hook is invoked, the changes have not yet been written to - * the database, because a database transaction is still in progress. The - * transaction is not finalized until the save operation is entirely completed - * and $node->save() goes out of scope. You should not rely on data in the - * database at this time as it is not updated yet. You should also note that any - * write/update database queries executed from this hook are also not committed - * immediately. Check $node->save() and db_transaction() for more info. - * - * @param \Drupal\node\NodeInterface $node - * The node that is being updated. - * - * @ingroup node_api_hooks - */ -function hook_node_update(\Drupal\node\NodeInterface $node) { - db_update('mytable') - ->fields(array('extra' => $node->extra)) - ->condition('nid', $node->id()) - ->execute(); -} - /** * Act on a node being indexed for searching. * @@ -697,7 +390,7 @@ function hook_node_update(\Drupal\node\NodeInterface $node) { * @return string * Additional node information to be indexed. * - * @ingroup node_api_hooks + * @ingroup entity_crud */ function hook_node_update_index(\Drupal\node\NodeInterface $node, $langcode) { $text = ''; @@ -729,7 +422,7 @@ function hook_node_update_index(\Drupal\node\NodeInterface $node, $langcode) { * @param $form_state * The form state array. * - * @ingroup node_api_hooks + * @ingroup entity_crud */ function hook_node_validate(\Drupal\node\NodeInterface $node, $form, &$form_state) { if (isset($node->end) && isset($node->start)) { @@ -756,7 +449,7 @@ function hook_node_validate(\Drupal\node\NodeInterface $node, $form, &$form_stat * @param $form_state * The form state array. * - * @ingroup node_api_hooks + * @ingroup entity_crud */ function hook_node_submit(\Drupal\node\NodeInterface $node, $form, &$form_state) { // Decompose the selected menu parent option into 'menu_name' and 'plid', if @@ -766,82 +459,6 @@ function hook_node_submit(\Drupal\node\NodeInterface $node, $form, &$form_state) } } -/** - * Act on a node that is being assembled before rendering. - * - * The module may add elements to a node's renderable array array prior to - * rendering. - * - * When $view_mode is 'rss', modules can also add extra RSS elements and - * namespaces to $node->rss_elements and $node->rss_namespaces respectively for - * the RSS item generated for this node. - * For details on how this is used, see node_feed(). - * - * @param array &$build - * A renderable array representing the node content. - * @param \Drupal\node\NodeInterface $node - * The node that is being assembled for rendering. - * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display - * The entity view display holding the display options configured for the node - * components. - * @param string $view_mode - * The $view_mode parameter from node_view(). - * @param string $langcode - * The language code used for rendering. - * - * @see forum_node_view() - * @see hook_entity_view() - * - * @ingroup node_api_hooks - */ -function hook_node_view(array &$build, \Drupal\node\NodeInterface $node, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode, $langcode) { - // Only do the extra work if the component is configured to be displayed. - // This assumes a 'mymodule_addition' extra field has been defined for the - // node type in hook_entity_extra_field_info(). - if ($display->getComponent('mymodule_addition')) { - $build['mymodule_addition'] = array( - '#markup' => mymodule_addition($node), - '#theme' => 'mymodule_my_additional_field', - ); - } -} - -/** - * Alter the results of node_view(). - * - * This hook is called after the content has been assembled in a structured - * array and may be used for doing processing which requires that the complete - * node content structure has been built. - * - * If the module wishes to act on the rendered HTML of the node rather than the - * structured content array, it may use this hook to add a #post_render - * callback. Alternatively, it could also implement hook_preprocess_HOOK() for - * node.html.twig. See drupal_render() and _theme() documentation respectively - * for details. - * - * @param &$build - * A renderable array representing the node content. - * @param \Drupal\node\NodeInterface $node - * The node being rendered. - * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display - * The entity view display holding the display options configured for the node - * components. - * - * @see node_view() - * @see hook_entity_view_alter() - * - * @ingroup node_api_hooks - */ -function hook_node_view_alter(array &$build, \Drupal\node\NodeInterface $node, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) { - if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) { - // Change its weight. - $build['an_additional_field']['#weight'] = -10; - } - - // Add a #post_render callback to act on the rendered HTML of the node. - $build['#post_render'][] = 'my_module_node_post_render'; -} - /** * Provide additional methods of scoring for core search results for nodes. * @@ -883,7 +500,7 @@ function hook_node_view_alter(array &$build, \Drupal\node\NodeInterface $node, \ * - arguments: (optional) If any arguments are required for the score, they * can be specified in an array here. * - * @ingroup node_api_hooks + * @ingroup entity_crud */ function hook_ranking() { // If voting is disabled, we can avoid returning the array, no hard feelings. @@ -904,38 +521,6 @@ function hook_ranking() { } } -/** - * Respond to node type creation. - * - * @param \Drupal\node\NodeTypeInterface $type - * The node type entity that was created. - */ -function hook_node_type_insert(\Drupal\node\NodeTypeInterface $type) { - drupal_set_message(t('You have just created a content type with a machine name %type.', array('%type' => $type->id()))); -} - -/** - * Respond to node type updates. - * - * @param \Drupal\node\NodeTypeInterface $type - * The node type entity that was updated. - */ -function hook_node_type_update(\Drupal\node\NodeTypeInterface $type) { - if ($type->original->id() != $type->id()) { - drupal_set_message(t('You have just changed the machine name of a content type from %old_type to %type.', array('%old_type' => $type->original->id(), '%type' => $type->id()))); - } -} - -/** - * Respond to node type deletion. - * - * @param \Drupal\node\NodeTypeInterface $type - * The node type entity that was deleted. - */ -function hook_node_type_delete(\Drupal\node\NodeTypeInterface $type) { - drupal_set_message(t('You have just deleted a content type with the machine name %type.', array('%type' => $type->id()))); -} - /** * Alter the links of a node. * @@ -951,6 +536,7 @@ function hook_node_type_delete(\Drupal\node\NodeTypeInterface $type) { * * @see \Drupal\node\NodeViewBuilder::renderLinks() * @see \Drupal\node\NodeViewBuilder::buildLinks() + * @see entity_crud */ function hook_node_links_alter(array &$links, NodeInterface $entity, array &$context) { $links['mymodule'] = array( diff --git a/core/modules/node/node.module b/core/modules/node/node.module index 44ac84908bd2..a34ca8225c08 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -785,7 +785,7 @@ function node_user_cancel($edit, $account, $method) { } /** - * Implements hook_user_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for user entities. */ function node_user_predelete($account) { // Delete nodes (current revisions). @@ -1134,10 +1134,12 @@ function node_form_system_themes_admin_form_submit($form, &$form_state) { * default home page at path 'node', an RSS feed, a recent content block, etc.), * the process above is followed except that hook_node_access() is not called on * each node for performance reasons and for proper functioning of the pager - * system. When adding a node listing to your module, be sure to use a dynamic - * entity query and add a tag of "node_access". This will allow modules dealing + * system. When adding a node listing to your module, be sure to use an entity + * query, which will add a tag of "node_access". This will allow modules dealing * with node access to ensure only nodes to which the user has access are - * retrieved, through the use of hook_query_TAG_alter(). + * retrieved, through the use of hook_query_TAG_alter(). See the + * @link entity_api Entity API topic @endlink for more information on entity + * queries. * * Note: Even a single module returning NODE_ACCESS_DENY from hook_node_access() * will block access to the node. Therefore, implementers should take care to @@ -1628,7 +1630,7 @@ function node_reindex_node_search($nid) { } /** - * Implements hook_comment_insert(). + * Implements hook_ENTITY_TYPE_insert() for comment entities. */ function node_comment_insert($comment) { // Reindex the node when comments are added. @@ -1638,7 +1640,7 @@ function node_comment_insert($comment) { } /** - * Implements hook_comment_update(). + * Implements hook_ENTITY_TYPE_update() for comment entities. */ function node_comment_update($comment) { // Reindex the node when comments are changed. @@ -1648,7 +1650,7 @@ function node_comment_update($comment) { } /** - * Implements hook_comment_delete(). + * Implements hook_ENTITY_TYPE_delete() for comment entities. */ function node_comment_delete($comment) { // Reindex the node when comments are deleted. diff --git a/core/modules/node/src/Tests/NodeCreationTest.php b/core/modules/node/src/Tests/NodeCreationTest.php index 7ea8b4d2329b..a305ca54393d 100644 --- a/core/modules/node/src/Tests/NodeCreationTest.php +++ b/core/modules/node/src/Tests/NodeCreationTest.php @@ -20,7 +20,8 @@ class NodeCreationTest extends NodeTestBase { /** * Modules to enable. * - * Enable dummy module that implements hook_node_insert() for exceptions. + * Enable dummy module that implements hook_ENTITY_TYPE_insert() for + * exceptions (function node_test_exception_node_insert() ). * * @var array */ diff --git a/core/modules/node/src/Tests/NodeEntityViewModeAlterTest.php b/core/modules/node/src/Tests/NodeEntityViewModeAlterTest.php index 4f6345c4df81..a979ef8ae004 100644 --- a/core/modules/node/src/Tests/NodeEntityViewModeAlterTest.php +++ b/core/modules/node/src/Tests/NodeEntityViewModeAlterTest.php @@ -15,7 +15,7 @@ class NodeEntityViewModeAlterTest extends NodeTestBase { /** - * Enable dummy module that implements hook_node_view(). + * Enable dummy module that implements hook_ENTITY_TYPE_view() for nodes. */ public static $modules = array('node_test'); diff --git a/core/modules/node/src/Tests/NodeSaveTest.php b/core/modules/node/src/Tests/NodeSaveTest.php index eaafdd5dd086..75e3651261a4 100644 --- a/core/modules/node/src/Tests/NodeSaveTest.php +++ b/core/modules/node/src/Tests/NodeSaveTest.php @@ -89,7 +89,7 @@ function testTimestamps() { $node = $this->drupalGetNodeByTitle($edit['title'], TRUE); $this->assertEqual($node->getCreatedTime(), $created, 'Updating a node preserves "created" timestamp.'); - // Programmatically set the timestamps using hook_node_presave. + // Programmatically set the timestamps using hook_ENTITY_TYPE_presave(). $node->title = 'testing_node_presave'; $node->save(); @@ -124,8 +124,8 @@ function testTimestamps() { /** * Tests node presave and static node load cache. * - * This test determines changes in hook_node_presave() and verifies that the - * static node load cache is cleared upon save. + * This test determines changes in hook_ENTITY_TYPE_presave() and verifies + * that the static node load cache is cleared upon save. */ function testDeterminingChanges() { // Initial creation. @@ -156,9 +156,9 @@ function testDeterminingChanges() { /** * Tests saving a node on node insert. * - * This test ensures that a node has been fully saved when hook_node_insert() - * is invoked, so that the node can be saved again in a hook implementation - * without errors. + * This test ensures that a node has been fully saved when + * hook_ENTITY_TYPE_insert() is invoked, so that the node can be saved again + * in a hook implementation without errors. * * @see node_test_node_insert() */ diff --git a/core/modules/node/tests/modules/node_access_test/node_access_test.module b/core/modules/node/tests/modules/node_access_test/node_access_test.module index df3abbf7f2a2..696f29ef9bbf 100644 --- a/core/modules/node/tests/modules/node_access_test/node_access_test.module +++ b/core/modules/node/tests/modules/node_access_test/node_access_test.module @@ -157,7 +157,7 @@ function node_access_test_form_node_form_alter(&$form, $form_state) { } /** - * Implements hook_node_load(). + * Implements hook_ENTITY_TYPE_load() for node entities. */ function node_access_test_node_load($nodes) { $result = db_query('SELECT nid, private FROM {node_access_test} WHERE nid IN(:nids)', array(':nids' => array_keys($nodes))); @@ -167,21 +167,21 @@ function node_access_test_node_load($nodes) { } /** - * Implements hook_node_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for node entities. */ function node_access_test_node_predelete(NodeInterface $node) { db_delete('node_access_test')->condition('nid', $node->id())->execute(); } /** - * Implements hook_node_insert(). + * Implements hook_ENTITY_TYPE_insert() for node entities. */ function node_access_test_node_insert(NodeInterface $node) { _node_access_test_node_write($node); } /** - * Implements hook_nodeapi_update(). + * Implements hook_ENTITY_TYPE_update() for node entities. */ function node_access_test_node_update(NodeInterface $node) { _node_access_test_node_write($node); diff --git a/core/modules/node/tests/modules/node_test/node_test.module b/core/modules/node/tests/modules/node_test/node_test.module index 58624c372bb8..ed9af445f452 100644 --- a/core/modules/node/tests/modules/node_test/node_test.module +++ b/core/modules/node/tests/modules/node_test/node_test.module @@ -13,7 +13,7 @@ use Drupal\node\NodeInterface; /** - * Implements hook_node_view(). + * Implements hook_ENTITY_TYPE_view() for node entities. */ function node_test_node_view(array &$build, NodeInterface $node, EntityViewDisplayInterface $display, $view_mode) { if ($view_mode == 'rss') { @@ -39,7 +39,7 @@ function node_test_node_view(array &$build, NodeInterface $node, EntityViewDispl } /** - * Implements hook_ENTITY_TYPE_build_defaults_alter(). + * Implements hook_ENTITY_TYPE_build_defaults_alter() for node entities. */ function node_test_node_build_defaults_alter(array &$build, NodeInterface &$node, $view_mode = 'full', $langcode = NULL) { if ($view_mode == 'rss') { @@ -119,7 +119,7 @@ function node_test_node_grants_alter(&$grants, AccountInterface $account, $op) { } /** - * Implements hook_node_presave(). + * Implements hook_ENTITY_TYPE_presave() for node entities. */ function node_test_node_presave(NodeInterface $node) { if ($node->getTitle() == 'testing_node_presave') { @@ -137,7 +137,7 @@ function node_test_node_presave(NodeInterface $node) { } /** - * Implements hook_node_update(). + * Implements hook_ENTITY_TYPE_update() for node entities. */ function node_test_node_update(NodeInterface $node) { // Determine changes on update. @@ -160,7 +160,7 @@ function node_test_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\Entity } /** - * Implements hook_node_insert(). + * Implements hook_ENTITY_TYPE_insert() for node entities. * * This tests saving a node on node insert. * diff --git a/core/modules/node/tests/modules/node_test_exception/node_test_exception.module b/core/modules/node/tests/modules/node_test_exception/node_test_exception.module index b696ca48a011..b016fe871b1e 100644 --- a/core/modules/node/tests/modules/node_test_exception/node_test_exception.module +++ b/core/modules/node/tests/modules/node_test_exception/node_test_exception.module @@ -8,7 +8,7 @@ use Drupal\node\NodeInterface; /** - * Implements hook_node_insert(). + * Implements hook_ENTITY_TYPE_insert() for node entities. */ function node_test_exception_node_insert(NodeInterface $node) { if ($node->getTitle() == 'testing_transaction_exception') { diff --git a/core/modules/rdf/rdf.module b/core/modules/rdf/rdf.module index 7bfb13c0957a..1221147a7420 100644 --- a/core/modules/rdf/rdf.module +++ b/core/modules/rdf/rdf.module @@ -224,7 +224,7 @@ function rdf_entity_prepare_view($entity_type, array $entities, array $displays) } /** - * Implements hook_comment_load(). + * Implements hook_ENTITY_TYPE_load() for comment entities. */ function rdf_comment_load($comments) { foreach ($comments as $comment) { diff --git a/core/modules/statistics/statistics.module b/core/modules/statistics/statistics.module index bce72c749e93..fbcf70267cb1 100644 --- a/core/modules/statistics/statistics.module +++ b/core/modules/statistics/statistics.module @@ -48,7 +48,7 @@ function statistics_permission() { } /** - * Implements hook_node_view(). + * Implements hook_ENTITY_TYPE_view() for node entities. */ function statistics_node_view(array &$build, EntityInterface $node, EntityViewDisplayInterface $display, $view_mode) { if (!$node->isNew() && $view_mode == 'full' && node_is_page($node) && empty($node->in_preview)) { @@ -195,7 +195,7 @@ function _statistics_format_item($title, $path) { } /** - * Implements hook_node_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for node entities. */ function statistics_node_predelete(EntityInterface $node) { // clean up statistics table when node is deleted diff --git a/core/modules/system/core.api.php b/core/modules/system/core.api.php index 7a212cfa002d..ecbb006cead1 100644 --- a/core/modules/system/core.api.php +++ b/core/modules/system/core.api.php @@ -32,16 +32,16 @@ * @section store_retrieve Storing and retrieving data * * - @link entity_api Entities @endlink + * - @link field Fields @endlink * - @link config_api Configuration API @endlink * - @link state_api State API @endlink - * - @link field Fields @endlink - * - @link node_overview Node system @endlink * - @link views_overview Views @endlink * - @link database Database abstraction layer @endlink * * @section other_essentials Other essential APIs * * - @link plugin_api Plugins @endlink + * - @link container Services and the Dependency Injection Container @endlink * - @link i18n Internationalization @endlink * - @link cache Caching @endlink * - @link utility Utility classes and functions @endlink @@ -53,7 +53,6 @@ * * - @link batch Batch API @endlink * - @link queue Queue API @endlink - * - @link container Services and the Dependency Injection Container @endlink * - @link typed_data Typed Data @endlink * - @link testing Automated tests @endlink * - @link third_party Integrating third-party applications @endlink @@ -391,12 +390,15 @@ * entities), to provide an administrative overview for your entities. * - add and edit forms, or default form: Define a class (or two) that * extend(s) \Drupal\Core\Entity\EntityForm to provide add and edit forms - * for your entities. + * for your entities. For content entities, base class + * \Drupal\Core\Entity\ContentEntityForm is a better starting point. * - delete form: Define a class that extends * \Drupal\Core\Entity\EntityConfirmFormBase to provide a delete * confirmation form for your entities. - * - view_buider: For content entities, define a class that extends - * \Drupal\Core\Entity\EntityViewBuilder, to display a single entity. + * - view_builder: For content entities and config entities that need to be + * viewed, define a class that implements + * \Drupal\Core\Entity\EntityViewBuilderInterface (usually extending + * \Drupal\Core\Entity\EntityViewBuilder), to display a single entity. * - translation: For translatable content entities (if the 'translatable' * annotation has value TRUE), define a class that extends * \Drupal\content_translation\ContentTranslationHandler, to translate @@ -405,7 +407,14 @@ * - access: If your configuration entity has complex permissions, you might * need an access controller, implementing * \Drupal\Core\Entity\EntityAccessControllerInterface, but most entities - * can just use the 'admin_permission' annotation instead. + * can just use the 'admin_permission' annotation instead. Note that if you + * are creating your own access controller, you should override the + * checkAccess() and checkCreateAccess() methods, not access(). + * - storage: A class implementing + * \Drupal\Core\Entity\EntityStorageInterface. If not specified, content + * entities will use \Drupal\Core\Entity\ContentEntityDatabaseStorage, and + * config entities will use \Drupal\Core\Config\Entity\ConfigEntityStorage. + * You can extend one of these classes to provide custom behavior. * - For content entities, the annotation will refer to a number of database * tables and their fields. These annotation properties, such as 'base_table', * 'data_table', 'entity_keys', etc., are documented on @@ -436,7 +445,9 @@ * 'bundle_entity_type' annotation on the entity type class. For example, for * the Node entity, the bundle class is \Drupal\node\Entity\NodeType, whose * machine name is 'node_type'. This is the annotation value for - * 'bundle_entity_type' on the \Drupal\node\Entity\Node class. + * 'bundle_entity_type' on the \Drupal\node\Entity\Node class. Also, the + * bundle config entity type annotation must have a 'bundle_of' entry, + * giving the machine name of the entity type it is acting as a bundle for. * - Additional annotations can be seen on entity class examples such as * \Drupal\node\Entity\Node (content) and \Drupal\user\Entity\Role * (configuration). These annotations are documented on @@ -473,7 +484,25 @@ * "default" = "Drupal\block\BlockForm", * @endcode * - * @section load_query Loading and querying entities + * @section bundle Defining a content entity bundle + * For entity types that use bundles, such as Node (bundles are content types) + * and Taxonomy (bundles are vocabularies), modules and install profiles can + * define bundles by supplying default configuration in their config/install + * directories. (See the @link config_api Configuration API topic @endlink for + * general information about configuration.) + * + * There are several good examples of this in Drupal Core: + * - The Forum module defines a content type in node.type.forum.yml and a + * vocabulary in taxonomy.vocabulary.forums.yml + * - The Book module defines a content type in node.type.book.yml + * - The Standard install profile defines Page and Article content types in + * node.type.page.yml and node.type.article.yml, a Tags vocabulary in + * taxonomy.vocabulary.tags.yml, and a Node comment type in + * comment.type.comment.yml. This profile's configuration is especially + * instructive, because it also adds several fields to the Article type, and + * it sets up view and form display modes for the node types. + * + * @section load_query Loading, querying, and rendering entities * To load entities, use the entity storage manager, which is an object * implementing \Drupal\Core\Entity\EntityStorageInterface that you can * retrieve with: @@ -523,6 +552,24 @@ * $files = $storage->loadMultiple($fids); * @endcode * + * The normal way of viewing entities is by using a route, as described in the + * sections above. If for some reason you need to render an entity in code in a + * particular view mode, you can use an entity view builder, which is an object + * implementing \Drupal\Core\Entity\EntityViewBuilderInterface that you can + * retrieve with: + * @code + * $view_builder = \Drupal::entityManager()->getViewBuilder('your_entity_type'); + * // Or if you have a $container variable: + * $view_builder = $container->get('entity.manager')->getViewBuilder('your_entity_type'); + * @endcode + * Then, to build and render the entity: + * @code + * // You can omit the language ID if the default language is being used. + * $build = $view_builder->view($entity, 'view_mode_name', $language->id); + * // $build is a render array. + * $rendered = drupal_render($build); + * @endcode + * * @section sec_access Access checking on entities * Entity types define their access permission scheme in their annotation. * Access permissions can be quite complex, so you should not assume any @@ -536,25 +583,21 @@ * The interface related to access checking in entities and fields is * \Drupal\Core\Access\AccessibleInterface. * - * @see i18n - * @} - */ - -/** - * @defgroup node_overview Nodes Overview - * @{ - * Overview of how to interact with the Node system + * The default entity access controller invokes two hooks while checking + * access on a single entity: hook_entity_access() is invoked first, and + * then hook_ENTITY_TYPE_access() (where ENTITY_TYPE is the machine name + * of the entity type). If no module returns a TRUE or FALSE value from + * either of these hooks, then the entity's default access checking takes + * place. For create operations (creating a new entity), the hooks that + * are invoked are hook_entity_create_access() and + * hook_ENTITY_TYPE_create_access() instead. * - * @todo write this + * The Node entity type has a complex system for determining access, which + * developers can interact with. This is described in the + * @link node_access Node access topic. @endlink * - * Additional documentation paragraphs need to be written, and functions, - * classes, and interfaces need to be added to this topic. This topic should - * describe node access, the node classes/interfaces, and the node hooks that a - * developer would need to know about, at a high level, and link to more - * detailed information. - * - * @see node_access - * @see node_api_hooks + * @see i18n + * @see entity_crud * @} */ diff --git a/core/modules/system/entity.api.php b/core/modules/system/entity.api.php index da1d53ec22d5..1bab346dd20c 100644 --- a/core/modules/system/entity.api.php +++ b/core/modules/system/entity.api.php @@ -10,6 +10,231 @@ use Drupal\Core\Field\FieldDefinition; use Drupal\Core\Render\Element; +/** + * @defgroup entity_crud Entity CRUD, editing, and view hooks + * @{ + * Hooks used in various entity operations. + * + * Entity create, read, update, and delete (CRUD) operations are performed by + * entity storage classes; see the + * @link entity_api Entity API topic @endlink for more information. Most + * entities use or extend the default classes: + * \Drupal\Core\Entity\ContentEntityDatabaseStorage for content entities, and + * \Drupal\Core\Config\Entity\ConfigEntityStorage for configuration entities. + * For these entities, there is a set of hooks that is invoked for each + * CRUD operation, which module developers can implement to affect these + * operations; these hooks are actually invoked from methods on + * \Drupal\Core\Entity\EntityStorageBase. + * + * For content entities, viewing and rendering are handled by a view builder + * class; see the @link entity_api Entity API topic @endlink for more + * information. Most view builders extend or use the default class + * \Drupal\Core\Entity\EntityViewBuilder. + * + * Entity editing (including adding new entities) is handled by entity form + * classes; see the @link entity_api Entity API topic @endlink for more + * information. Most entity editing forms extend base classes + * \Drupal\Core\Entity\EntityForm or \Drupal\Core\Entity\ContentEntityForm. + * Note that many other operations, such as confirming deletion of entities, + * also use entity form classes. + * + * This topic lists all of the entity CRUD and view operations, and the hooks + * and other operations that are invoked (in order) for each operation. Some + * notes: + * - Whenever an entity hook is invoked, there is both a type-specific entity + * hook, and a generic entity hook. For instance, during a create operation on + * a node, first hook_node_create() and then hook_entity_create() would be + * invoked. + * - The entity-type-specific hooks are represented in the list below as + * hook_ENTITY_TYPE_... (hook_ENTITY_TYPE_create() in this example). To + * implement one of these hooks for an entity whose machine name is "foo", + * define a function called mymodule_foo_create(), for instance. Also note + * that the entity or array of entities that are passed into a specific-type + * hook are of the specific entity class, not the generic Entity class, so in + * your implementation, you can make the $entity argument something like $node + * and give it a specific type hint (which should normally be to the specific + * interface, such as \Drupal\Node\NodeInterface for nodes). + * - $storage in the code examples is assumed to be an entity storage + * class. See the @link entity_api Entity API topic @endlink for + * information on how to instantiate the correct storage class for an + * entity type. + * - $view_builder in the code examples is assumed to be an entity view builder + * class. See the @link entity_api Entity API topic @endlink for + * information on how to instantiate the correct view builder class for + * an entity type. + * - During many operations, static methods are called on the entity class, + * which implements \Drupal\Entity\EntityInterface. + * + * @section create Create operations + * To create an entity: + * @code + * $entity = $storage->create(); + * + * // Add code here to set properties on the entity. + * + * // Until you call save(), the entity is just in memory. + * $entity->save(); + * @endcode + * There is also a shortcut method on entity classes, which creates an entity + * with an array of provided property values: \Drupal\Core\Entity::create(). + * + * Hooks invoked during the create operation: + * - hook_ENTITY_TYPE_create() + * - hook_entity_create() + * + * See @ref save below for the save portion of the operation. + * + * @section load Read/Load operations + * To load (read) a single entity: + * @code + * $entity = $storage->load($id); + * @endcode + * To load multiple entities: + * @code + * $entities = $storage->loadMultiple($ids); + * @endcode + * Since load() calls loadMultiple(), these are really the same operation. + * Here is the order of hooks and other operations that take place during + * entity loading: + * - Entity is loaded from storage. + * - postLoad() is called on the entity class, passing in all of the loaded + * entities. + * - hook_entity_load() + * - hook_ENTITY_TYPE_load() + * + * When an entity is loaded, normally the default entity revision is loaded. + * It is also possible to load a different revision, for entities that support + * revisions, with this code: + * @code + * $entity = $storage->loadRevision($revision_id); + * @endcode + * This involves the same hooks and operations as regular entity loading. + * + * @section save Save operations + * To update an existing entity, you will need to load it, change properties, + * and then save; as described above, when creating a new entity, you will also + * need to save it. Here is the order of hooks and other events that happen + * during an entity save: + * - preSave() is called on the entity object, and field objects. + * - hook_ENTITY_TYPE_presave() + * - hook_entity_presave() + * - Entity is saved to storage. + * - For updates on content entities, if there is a translation added that + * was not previously present: + * - hook_ENTITY_TYPE_translation_insert() + * - hook_entity_translation_insert() + * - For updates on content entities, if there was a translation removed: + * - hook_ENTITY_TYPE_translation_delete() + * - hook_entity_translation_delete() + * - postSave() is called on the entity object. + * - hook_ENTITY_TYPE_insert() (new) or hook_ENTITY_TYPE_update() (update) + * - hook_entity_insert() (new) or hook_entity_update() (update) + * + * Some specific entity types invoke hooks during preSave() or postSave() + * operations. Examples: + * - Field configuration preSave(): hook_field_config_update_forbid() + * - Node postSave(): hook_node_access_records() and + * hook_node_access_records_alter() + * - Config entities that are acting as entity bundles, in postSave(): + * hook_entity_bundle_create() or hook_entity_bundle_rename() as appropriate + * - Comment: hook_comment_publish() and hook_comment_unpublish() as + * appropriate. + * + * @section edit Editing operations + * When an entity's add/edit form is used to add or edit an entity, there + * are several hooks that are invoked: + * - hook_entity_prepare_form() + * - hook_ENTITY_TYPE_prepare_form() + * - hook_entity_form_display_alter() (for content entities only) + * + * Some specific entity types have additional hooks that are run during + * various steps in the process: + * - Node entities: hook_node_validate() and hook_submit(). + * + * @section delete Delete operations + * To delete one or more entities, load them and then delete them: + * @code + * $entities = $storage->loadMultiple($ids); + * $storage->delete($entities); + * @endcode + * + * During the delete operation, the following hooks and other events happen: + * - preDelete() is called on the entity class. + * - hook_ENTITY_TYPE_predelete() + * - hook_entity_predelete() + * - Entity and field information is removed from storage. + * - postDelete() is called on the entity class. + * - hook_ENTITY_TYPE_delete() + * - hook_entity_delete() + * + * Some specific entity types invoke hooks during the delete process. Examples: + * - Entity bundle postDelete(): hook_entity_bundle_delete() + * + * Individual revisions of an entity can also be deleted: + * @code + * $storage->deleteRevision($revision_id); + * @endcode + * This operation invokes the following operations and hooks: + * - Revision is loaded (see @ref load above). + * - Revision and field information is removed from the database. + * - hook_ENTITY_TYPE_revision_delete() + * - hook_entity_revision_delete() + * + * @section view View/render operations + * To make a render array for a loaded entity: + * @code + * // You can omit the language ID if the default language is being used. + * $build = $view_builder->view($entity, 'view_mode_name', $language->id); + * @endcode + * You can also use the viewMultiple() method to view multiple entities. + * + * Hooks invoked during the operation of building a render array: + * - hook_entity_view_mode_alter() + * - hook_ENTITY_TYPE_build_defaults_alter() + * - hook_entity_build_defaults_alter() + * + * View builders for some types override these hooks, notably: + * - The Tour view builder does not invoke any hooks. + * - The Block view builder invokes hook_block_view_alter() and + * hook_block_view_BASE_BLOCK_ID_alter(). Note that in other view builders, + * the view alter hooks are run later in the process. + * + * During the rendering operation, the default entity viewer runs the following + * hooks and operations in the pre-render step: + * - hook_entity_view_display_alter() + * - hook_entity_prepare_view() + * - Entity fields are loaded, and render arrays are built for them using + * their formatters. + * - hook_entity_display_build_alter() + * - hook_ENTITY_TYPE_view() + * - hook_entity_view() + * - hook_ENTITY_TYPE_view_alter() + * - hook_entity_view_alter() + * + * Some specific builders have specific hooks: + * - The Node view builder invokes hook_node_links_alter(). + * - The Comment view builder invokes hook_comment_links_alter(). + * + * After this point in rendering, the theme system takes over. See the + * @link theme_render Theme system and render API topic @endlink for more + * information. + * + * @section misc Other entity hooks + * Some types of entities invoke hooks for specific operations: + * - Searching nodes: + * - hook_ranking() + * - Query is executed to find matching nodes + * - Resulting node is loaded + * - Node render array is built + * - comment_node_update_index() is called (this adds "N comments" text) + * - hook_node_search_result() + * - Search indexing nodes: + * - Node is loaded + * - Node render array is built + * - hook_node_update_index() + * @} + */ + /** * @addtogroup hooks * @{ @@ -32,6 +257,10 @@ * deny access. * * @see \Drupal\Core\Entity\EntityAccessController + * @see hook_entity_create_access() + * @see hook_ENTITY_TYPE_access() + * + * @ingroup entity_api */ function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account, $langcode) { return NULL; @@ -54,6 +283,10 @@ function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operat * deny access. * * @see \Drupal\Core\Entity\EntityAccessController + * @see hook_ENTITY_TYPE_create_access() + * @see hook_entity_access() + * + * @ingroup entity_api */ function hook_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account, $langcode) { return NULL; @@ -72,6 +305,10 @@ function hook_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $o * deny access. * * @see \Drupal\Core\Entity\EntityAccessController + * @see hook_entity_access() + * @see hook_ENTITY_TYPE_create_access() + * + * @ingroup entity_api */ function hook_entity_create_access(\Drupal\Core\Session\AccountInterface $account, $langcode) { return NULL; @@ -90,6 +327,10 @@ function hook_entity_create_access(\Drupal\Core\Session\AccountInterface $accoun * deny access. * * @see \Drupal\Core\Entity\EntityAccessController + * @see hook_ENTITY_TYPE_access() + * @see hook_entity_create_access() + * + * @ingroup entity_api */ function hook_ENTITY_TYPE_create_access(\Drupal\Core\Session\AccountInterface $account, $langcode) { return NULL; @@ -198,6 +439,8 @@ function hook_entity_bundle_info_alter(&$bundles) { * The type of $entity; e.g. 'node' or 'user'. * @param string $bundle * The name of the bundle. + * + * @see entity_crud */ function hook_entity_bundle_create($entity_type_id, $bundle) { // When a new bundle is created, the menu needs to be rebuilt to add the @@ -216,6 +459,8 @@ function hook_entity_bundle_create($entity_type_id, $bundle) { * The previous name of the bundle. * @param string $bundle_new * The new name of the bundle. + * + * @see entity_crud */ function hook_entity_bundle_rename($entity_type_id, $bundle_old, $bundle_new) { // Update the settings associated with the bundle in my_module.settings. @@ -237,6 +482,8 @@ function hook_entity_bundle_rename($entity_type_id, $bundle_old, $bundle_new) { * The type of entity; for example, 'node' or 'user'. * @param string $bundle * The bundle that was just deleted. + * + * @ingroup entity_crud */ function hook_entity_bundle_delete($entity_type_id, $bundle) { // Remove the settings associated with the bundle in my_module.settings. @@ -256,6 +503,9 @@ function hook_entity_bundle_delete($entity_type_id, $bundle) { * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity object. + * + * @ingroup entity_crud + * @see hook_ENTITY_TYPE_create() */ function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) { if ($entity instanceof ContentEntityInterface && !$entity->foo->value) { @@ -263,6 +513,24 @@ function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) { } } +/** + * Act on a newly created entity of a specific type. + * + * This hook runs after a new entity object has just been instantiated. It can + * be used to set initial values, e.g. to provide defaults. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object. + * + * @ingroup entity_crud + * @see hook_entity_create() + */ +function hook_ENTITY_TYPE_create(\Drupal\Core\Entity\EntityInterface $entity) { + if (!$entity->foo->value) { + $entity->foo->value = 'some_initial_value'; + } +} + /** * Act on entities when loaded. * @@ -273,6 +541,9 @@ function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) { * The entities keyed by entity ID. * @param string $entity_type_id * The type of entities being loaded (i.e. node, user, comment). + * + * @ingroup entity_crud + * @see hook_ENTITY_TYPE_load() */ function hook_entity_load($entities, $entity_type_id) { foreach ($entities as $entity) { @@ -281,13 +552,50 @@ function hook_entity_load($entities, $entity_type_id) { } /** - * Act on an entity before it is about to be created or updated. + * Act on entities of a specific type when loaded. + * + * @param array $entities + * The entities keyed by entity ID. + * + * @ingroup entity_crud + * @see hook_entity_load() + */ +function hook_ENTITY_TYPE_load($entities) { + foreach ($entities as $entity) { + $entity->foo = mymodule_add_something($entity); + } +} + +/** + * Act on an entity before it is created or updated. * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity object. + * + * @ingroup entity_crud + * @see hook_ENTITY_TYPE_presave() */ function hook_entity_presave(Drupal\Core\Entity\EntityInterface $entity) { - $entity->changed = REQUEST_TIME; + if ($entity instanceof ContentEntityInterface && $entity->isTranslatable()) { + $attributes = \Drupal::request()->attributes; + \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->id, $attributes->get('source_langcode')); + } +} + +/** + * Act on a specific type of entity before it is created or updated. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object. + * + * @ingroup entity_crud + * @see hook_entity_presave() + */ +function hook_ENTITY_TYPE_presave(Drupal\Core\Entity\EntityInterface $entity) { + if ($entity->isTranslatable()) { + $attributes = \Drupal::request()->attributes; + \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->id, $attributes->get('source_langcode')); + } } /** @@ -298,6 +606,9 @@ function hook_entity_presave(Drupal\Core\Entity\EntityInterface $entity) { * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity object. + * + * @ingroup entity_crud + * @see hook_ENTITY_TYPE_insert() */ function hook_entity_insert(Drupal\Core\Entity\EntityInterface $entity) { // Insert the new entity into a fictional table of all entities. @@ -311,6 +622,29 @@ function hook_entity_insert(Drupal\Core\Entity\EntityInterface $entity) { ->execute(); } +/** + * Respond to creation of a new entity of a particular type. + * + * This hook runs once the entity has been stored. Note that hook + * implementations may not alter the stored entity data. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object. + * + * @ingroup entity_crud + * @see hook_entity_insert() + */ +function hook_ENTITY_TYPE_insert(Drupal\Core\Entity\EntityInterface $entity) { + // Insert the new entity into a fictional table of this type of entity. + db_insert('example_entity') + ->fields(array( + 'id' => $entity->id(), + 'created' => REQUEST_TIME, + 'updated' => REQUEST_TIME, + )) + ->execute(); +} + /** * Respond to updates to an entity. * @@ -319,6 +653,9 @@ function hook_entity_insert(Drupal\Core\Entity\EntityInterface $entity) { * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity object. + * + * @ingroup entity_crud + * @see hook_ENTITY_TYPE_update() */ function hook_entity_update(Drupal\Core\Entity\EntityInterface $entity) { // Update the entity's entry in a fictional table of all entities. @@ -331,6 +668,28 @@ function hook_entity_update(Drupal\Core\Entity\EntityInterface $entity) { ->execute(); } +/** + * Respond to updates to an entity of a particular type. + * + * This hook runs once the entity storage has been updated. Note that hook + * implementations may not alter the stored entity data. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object. + * + * @ingroup entity_crud + * @see hook_entity_update() + */ +function hook_ENTITY_TYPE_update(Drupal\Core\Entity\EntityInterface $entity) { + // Update the entity's entry in a fictional table of this type of entity. + db_update('example_entity') + ->fields(array( + 'updated' => REQUEST_TIME, + )) + ->condition('id', $entity->id()) + ->execute(); +} + /** * Respond to creation of a new entity translation. * @@ -339,6 +698,9 @@ function hook_entity_update(Drupal\Core\Entity\EntityInterface $entity) { * * @param \Drupal\Core\Entity\EntityInterface $translation * The entity object of the translation just stored. + * + * @ingroup entity_crud + * @see hook_ENTITY_TYPE_translation_insert() */ function hook_entity_translation_insert(\Drupal\Core\Entity\EntityInterface $translation) { $variables = array( @@ -348,6 +710,26 @@ function hook_entity_translation_insert(\Drupal\Core\Entity\EntityInterface $tra \Drupal::logger('example')->notice('The @language translation of @label has just been stored.', $variables); } +/** + * Respond to creation of a new entity translation of a particular type. + * + * This hook runs once the entity translation has been stored. Note that hook + * implementations may not alter the stored entity translation data. + * + * @param \Drupal\Core\Entity\EntityInterface $translation + * The entity object of the translation just stored. + * + * @ingroup entity_crud + * @see hook_entity_translation_insert() + */ +function hook_ENTITY_TYPE_translation_insert(\Drupal\Core\Entity\EntityInterface $translation) { + $variables = array( + '@language' => $translation->language()->name, + '@label' => $translation->getUntranslated()->label(), + ); + \Drupal::logger('example')->notice('The @language translation of @label has just been stored.', $variables); +} + /** * Respond to entity translation deletion. * @@ -355,6 +737,9 @@ function hook_entity_translation_insert(\Drupal\Core\Entity\EntityInterface $tra * * @param \Drupal\Core\Entity\EntityInterface $entity * The original entity object. + * + * @ingroup entity_crud + * @see hook_ENTITY_TYPE_translation_delete() */ function hook_entity_translation_delete(\Drupal\Core\Entity\EntityInterface $translation) { $languages = \Drupal::languageManager()->getLanguages(); @@ -365,11 +750,34 @@ function hook_entity_translation_delete(\Drupal\Core\Entity\EntityInterface $tra \Drupal::logger('example')->notice('The @language translation of @label has just been deleted.', $variables); } +/** + * Respond to entity translation deletion of a particular type. + * + * This hook runs once the entity translation has been deleted from storage. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The original entity object. + * + * @ingroup entity_crud + * @see hook_entity_translation_delete() + */ +function hook_ENTITY_TYPE_translation_delete(\Drupal\Core\Entity\EntityInterface $translation) { + $languages = \Drupal::languageManager()->getLanguages(); + $variables = array( + '@language' => $languages[$langcode]->name, + '@label' => $entity->label(), + ); + \Drupal::logger('example')->notice('The @language translation of @label has just been deleted.', $variables); +} + /** * Act before entity deletion. * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity object for the entity that is about to be deleted. + * + * @ingroup entity_crud + * @see hook_ENTITY_TYPE_predelete() */ function hook_entity_predelete(Drupal\Core\Entity\EntityInterface $entity) { // Count references to this entity in a custom table before they are removed @@ -390,6 +798,34 @@ function hook_entity_predelete(Drupal\Core\Entity\EntityInterface $entity) { ->execute(); } +/** + * Act before entity deletion of a particular entity type. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object for the entity that is about to be deleted. + * + * @ingroup entity_crud + * @see hook_entity_predelete() + */ +function hook_ENTITY_TYPE_predelete(Drupal\Core\Entity\EntityInterface $entity) { + // Count references to this entity in a custom table before they are removed + // upon entity deletion. + $id = $entity->id(); + $type = $entity->getEntityTypeId(); + $count = db_select('example_entity_data') + ->condition('type', $type) + ->condition('id', $id) + ->countQuery() + ->execute() + ->fetchField(); + + // Log the count in a table that records this statistic for deleted entities. + db_merge('example_deleted_entity_statistics') + ->key(array('type' => $type, 'id' => $id)) + ->fields(array('count' => $count)) + ->execute(); +} + /** * Respond to entity deletion. * @@ -397,6 +833,9 @@ function hook_entity_predelete(Drupal\Core\Entity\EntityInterface $entity) { * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity object for the entity that has been deleted. + * + * @ingroup entity_crud + * @see hook_ENTITY_TYPE_delete() */ function hook_entity_delete(Drupal\Core\Entity\EntityInterface $entity) { // Delete the entity's entry from a fictional table of all entities. @@ -406,6 +845,25 @@ function hook_entity_delete(Drupal\Core\Entity\EntityInterface $entity) { ->execute(); } +/** + * Respond to entity deletion of a particular type. + * + * This hook runs once the entity has been deleted from the storage. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object for the entity that has been deleted. + * + * @ingroup entity_crud + * @see hook_entity_delete() + */ +function hook_ENTITY_TYPE_delete(Drupal\Core\Entity\EntityInterface $entity) { + // Delete the entity's entry from a fictional table of all entities. + db_delete('example_entity') + ->condition('type', $entity->getEntityTypeId()) + ->condition('id', $entity->id()) + ->execute(); +} + /** * Respond to entity revision deletion. * @@ -413,9 +871,33 @@ function hook_entity_delete(Drupal\Core\Entity\EntityInterface $entity) { * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity object for the entity revision that has been deleted. + * + * @ingroup entity_crud + * @see hook_ENTITY_TYPE_revision_delete() */ function hook_entity_revision_delete(Drupal\Core\Entity\EntityInterface $entity) { - // @todo: code example + $referenced_files_by_field = _editor_get_file_uuids_by_field($entity); + foreach ($referenced_files_by_field as $field => $uuids) { + _editor_delete_file_usage($uuids, $entity, 1); + } +} + +/** + * Respond to entity revision deletion of a particular type. + * + * This hook runs once the entity revision has been deleted from the storage. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object for the entity revision that has been deleted. + * + * @ingroup entity_crud + * @see hook_entity_revision_delete() + */ +function hook_ENTITY_TYPE_revision_delete(Drupal\Core\Entity\EntityInterface $entity) { + $referenced_files_by_field = _editor_get_file_uuids_by_field($entity); + foreach ($referenced_files_by_field as $field => $uuids) { + _editor_delete_file_usage($uuids, $entity, 1); + } } /** @@ -453,9 +935,9 @@ function hook_entity_query_alter(\Drupal\Core\Entity\Query\QueryInterface $query * drupal_render(). * * @see hook_entity_view_alter() - * @see hook_comment_view() - * @see hook_node_view() - * @see hook_user_view() + * @see hook_ENTITY_TYPE_view() + * + * @ingroup entity_crud */ function hook_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode, $langcode) { // Only do the extra work if the component is configured to be displayed. @@ -470,7 +952,43 @@ function hook_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $en } /** - * Alter the results of ENTITY_view(). + * Act on entities of a particular type being assembled before rendering. + * + * @param &$build + * A renderable array representing the entity content. + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object. + * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display + * The entity view display holding the display options configured for the + * entity components. + * @param $view_mode + * The view mode the entity is rendered in. + * @param $langcode + * The language code used for rendering. + * + * The module may add elements to $build prior to rendering. The + * structure of $build is a renderable array as expected by + * drupal_render(). + * + * @see hook_ENTITY_TYPE_view_alter() + * @see hook_entity_view() + * + * @ingroup entity_crud + */ +function hook_ENTITY_TYPE_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode, $langcode) { + // Only do the extra work if the component is configured to be displayed. + // This assumes a 'mymodule_addition' extra field has been defined for the + // entity bundle in hook_entity_extra_field_info(). + if ($display->getComponent('mymodule_addition')) { + $build['mymodule_addition'] = array( + '#markup' => mymodule_addition($entity), + '#theme' => 'mymodule_my_additional_field', + ); + } +} + +/** + * Alter the results of the entity build array. * * This hook is called after the content has been assembled in a structured * array and may be used for doing processing which requires that the complete @@ -491,10 +1009,9 @@ function hook_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $en * entity components. * * @see hook_entity_view() - * @see hook_comment_view_alter() - * @see hook_node_view_alter() - * @see hook_taxonomy_term_view_alter() - * @see hook_user_view_alter() + * @see hook_ENTITY_TYPE_view_alter() + * + * @ingroup entity_crud */ function hook_entity_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) { if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) { @@ -506,6 +1023,42 @@ function hook_entity_view_alter(array &$build, Drupal\Core\Entity\EntityInterfac } } +/** + * Alter the results of the entity build array for a particular entity type. + * + * This hook is called after the content has been assembled in a structured + * array and may be used for doing processing which requires that the complete + * entity content structure has been built. + * + * If a module wishes to act on the rendered HTML of the entity rather than the + * structured content array, it may use this hook to add a #post_render + * callback. Alternatively, it could also implement hook_preprocess_HOOK() for + * the particular entity type template, if there is one (e.g., node.html.twig). + * See drupal_render() and _theme() for details. + * + * @param array &$build + * A renderable array representing the entity content. + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object being rendered. + * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display + * The entity view display holding the display options configured for the + * entity components. + * + * @see hook_ENTITY_TYPE_view() + * @see hook_entity_view_alter() + * + * @ingroup entity_crud + */ +function hook_ENTITY_TYPE_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) { + if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) { + // Change its weight. + $build['an_additional_field']['#weight'] = -10; + + // Add a #post_render callback to act on the rendered HTML of the entity. + $build['#post_render'][] = 'my_module_node_post_render'; + } +} + /** * Act on entities as they are being prepared for view. * @@ -522,6 +1075,8 @@ function hook_entity_view_alter(array &$build, Drupal\Core\Entity\EntityInterfac * for the entity components, keyed by bundle name. * @param string $view_mode * The view mode. + * + * @ingroup entity_crud */ function hook_entity_prepare_view($entity_type_id, array $entities, array $displays, $view_mode) { // Load a specific node into the user object for later theming. @@ -554,6 +1109,8 @@ function hook_entity_prepare_view($entity_type_id, array $entities, array $displ * @param array $context * Array with additional context information, currently only contains the * langcode the entity is viewed in. + * + * @ingroup entity_crud */ function hook_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInterface $entity, $context) { // For nodes, change the view mode when it is teaser. @@ -563,7 +1120,7 @@ function hook_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInter } /** - * Alters entity renderable values before cache checking in drupal_render(). + * Alter entity renderable values before cache checking in drupal_render(). * * Invoked for a specific entity type. * @@ -582,13 +1139,16 @@ function hook_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInter * * @see drupal_render() * @see \Drupal\Core\Entity\EntityViewBuilder + * @see hook_entity_build_defaults_alter() + * + * @ingroup entity_crud */ function hook_ENTITY_TYPE_build_defaults_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, $view_mode, $langcode) { } /** - * Alters entity renderable values before cache checking in drupal_render(). + * Alter entity renderable values before cache checking in drupal_render(). * * The values in the #cache key of the renderable array are used to determine if * a cache entry exists for the entity's rendered output. Ideally only values @@ -605,13 +1165,16 @@ function hook_ENTITY_TYPE_build_defaults_alter(array &$build, \Drupal\Core\Entit * * @see drupal_render() * @see \Drupal\Core\Entity\EntityViewBuilder + * @see hook_ENTITY_TYPE_build_defaults_alter() + * + * @ingroup entity_crud */ function hook_entity_build_defaults_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, $view_mode, $langcode) { } /** - * Alters the settings used for displaying an entity. + * Alter the settings used for displaying an entity. * * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display * The entity view display that will be used to display the entity @@ -621,6 +1184,8 @@ function hook_entity_build_defaults_alter(array &$build, \Drupal\Core\Entity\Ent * - entity_type: The entity type, e.g., 'node' or 'user'. * - bundle: The bundle, e.g., 'page' or 'article'. * - view_mode: The view mode, e.g. 'full', 'teaser'... + * + * @ingroup entity_crud */ function hook_entity_view_display_alter(\Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, array $context) { // Leave field labels out of the search index. @@ -644,6 +1209,8 @@ function hook_entity_view_display_alter(\Drupal\Core\Entity\Display\EntityViewDi * - entity: The entity being rendered. * - view_mode: The view mode; for example, 'full' or 'teaser'. * - display: The EntityDisplay holding the display options. + * + * @ingroup entity_crud */ function hook_entity_display_build_alter(&$build, $context) { // Append RDF term mappings on displayed taxonomy links. @@ -678,6 +1245,9 @@ function hook_entity_display_build_alter(&$build, $context) { * An associative array containing the current state of the form. * * @see \Drupal\Core\Entity\EntityForm::prepareEntity() + * @see hook_ENTITY_TYPE_prepare_form() + * + * @ingroup entity_crud */ function hook_entity_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $operation, array &$form_state) { if ($operation == 'edit') { @@ -687,7 +1257,33 @@ function hook_entity_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $ } /** - * Alters the settings used for displaying an entity form. + * Acts on a particular type of entity object about to be in an entity form. + * + * This can be typically used to pre-fill entity values or change the form state + * before the entity form is built. It is invoked just once when first building + * the entity form. Rebuilds will not trigger a new invocation. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity that is about to be shown on the form. + * @param $operation + * The current operation. + * @param array $form_state + * An associative array containing the current state of the form. + * + * @see \Drupal\Core\Entity\EntityForm::prepareEntity() + * @see hook_entity_prepare_form() + * + * @ingroup entity_crud + */ +function hook_ENTITY_TYPE_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $operation, array &$form_state) { + if ($operation == 'edit') { + $entity->label->value = 'Altered label'; + $form_state['mymodule']['label_altered'] = TRUE; + } +} + +/** + * Alter the settings used for displaying an entity form. * * @param \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display * The entity_form_display object that will be used to display the entity form @@ -697,6 +1293,8 @@ function hook_entity_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $ * - entity_type: The entity type, e.g., 'node' or 'user'. * - bundle: The bundle, e.g., 'page' or 'article'. * - form_mode: The form mode, e.g. 'default', 'profile', 'register'... + * + * @ingroup entity_crud */ function hook_entity_form_display_alter(\Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display, array $context) { // Hide the 'user_picture' field from the register form. @@ -736,7 +1334,7 @@ function hook_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterface $en } /** - * Alters base field definitions for a content entity type. + * Alter base field definitions for a content entity type. * * @param \Drupal\Core\Field\FieldDefinitionInterface[] $fields * The array of base field definitions for the entity type. @@ -792,7 +1390,7 @@ function hook_entity_bundle_field_info(\Drupal\Core\Entity\EntityTypeInterface $ } /** - * Alters bundle field definitions. + * Alter bundle field definitions. * * @param \Drupal\Core\Field\FieldDefinitionInterface[] $fields * The array of bundle field definitions. @@ -845,7 +1443,7 @@ function hook_entity_field_storage_info(\Drupal\Core\Entity\EntityTypeInterface } /** - * Alters field storage definitions for a content entity type. + * Alter field storage definitions for a content entity type. * * @param \Drupal\Core\Field\FieldStorageDefinitionInterface[] $fields * The array of field storage definitions for the entity type. @@ -928,7 +1526,7 @@ function hook_entity_field_access($operation, \Drupal\Core\Field\FieldDefinition } /** - * Alters the default access behavior for a given field. + * Alter the default access behavior for a given field. * * Use this hook to override access grants from another module. Note that the * original default access flag is masked under the ':default' key. diff --git a/core/modules/system/src/Tests/Entity/EntityCrudHookTest.php b/core/modules/system/src/Tests/Entity/EntityCrudHookTest.php index 7067f9b6db9f..2f41f43cae6f 100644 --- a/core/modules/system/src/Tests/Entity/EntityCrudHookTest.php +++ b/core/modules/system/src/Tests/Entity/EntityCrudHookTest.php @@ -17,13 +17,13 @@ * deleting an entity. * * Tested hooks are: - * - hook_entity_insert() - * - hook_entity_load() - * - hook_entity_update() - * - hook_entity_predelete() - * - hook_entity_delete() - * As well as all type-specific hooks, like hook_node_insert(), - * hook_comment_update(), etc. + * - hook_entity_insert() and hook_ENTITY_TYPE_insert() + * - hook_entity_load() and hook_ENTITY_TYPE_load() + * - hook_entity_update() and hook_ENTITY_TYPE_update() + * - hook_entity_predelete() and hook_ENTITY_TYPE_predelete() + * - hook_entity_delete() and hook_ENTITY_TYPE_delete() + * + * These hooks are each tested for several entity types. * * @group Entity */ diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 3d67b659e5bf..4a57520bdbcc 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -1007,7 +1007,7 @@ function system_form_user_register_form_alter(&$form, &$form_state) { } /** - * Implements hook_user_presave(). + * Implements hook_ENTITY_TYPE_presave() for user entities. */ function system_user_presave(UserInterface $account) { $config = \Drupal::config('system.date'); diff --git a/core/modules/system/tests/modules/entity_crud_hook_test/entity_crud_hook_test.module b/core/modules/system/tests/modules/entity_crud_hook_test/entity_crud_hook_test.module index e88ae9978616..c7f20c366d84 100644 --- a/core/modules/system/tests/modules/entity_crud_hook_test/entity_crud_hook_test.module +++ b/core/modules/system/tests/modules/entity_crud_hook_test/entity_crud_hook_test.module @@ -15,49 +15,49 @@ function entity_crud_hook_test_entity_create(EntityInterface $entity) { } /** - * Implements hook_block_create(). + * Implements hook_ENTITY_TYPE_create() for block entities. */ function entity_crud_hook_test_block_create() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_comment_create(). + * Implements hook_ENTITY_TYPE_create() for comment entities. */ function entity_crud_hook_test_comment_create() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_file_create(). + * Implements hook_ENTITY_TYPE_create() for file entities. */ function entity_crud_hook_test_file_create() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_node_create(). + * Implements hook_ENTITY_TYPE_create() for node entities. */ function entity_crud_hook_test_node_create() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_taxonomy_term_create(). + * Implements hook_ENTITY_TYPE_create() for taxonomy_term entities. */ function entity_crud_hook_test_taxonomy_term_create() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_taxonomy_vocabulary_create(). + * Implements hook_ENTITY_TYPE_create() for taxonomy_vocabulary entities. */ function entity_crud_hook_test_taxonomy_vocabulary_create() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_user_create(). + * Implements hook_ENTITY_TYPE_create() for user entities. */ function entity_crud_hook_test_user_create() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); @@ -71,49 +71,49 @@ function entity_crud_hook_test_entity_presave(EntityInterface $entity) { } /** - * Implements hook_block_presave(). + * Implements hook_ENTITY_TYPE_presave() for block entities. */ function entity_crud_hook_test_block_presave() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_comment_presave(). + * Implements hook_ENTITY_TYPE_presave() for comment entities. */ function entity_crud_hook_test_comment_presave() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_file_presave(). + * Implements hook_ENTITY_TYPE_presave() for file entities. */ function entity_crud_hook_test_file_presave() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_node_presave(). + * Implements hook_ENTITY_TYPE_presave() for node entities. */ function entity_crud_hook_test_node_presave() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_taxonomy_term_presave(). + * Implements hook_ENTITY_TYPE_presave() for taxonomy_term entities. */ function entity_crud_hook_test_taxonomy_term_presave() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_taxonomy_vocabulary_presave(). + * Implements hook_ENTITY_TYPE_presave() for taxonomy_vocabulary entities. */ function entity_crud_hook_test_taxonomy_vocabulary_presave() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_user_presave(). + * Implements hook_ENTITY_TYPE_presave() for user entities. */ function entity_crud_hook_test_user_presave() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); @@ -127,49 +127,49 @@ function entity_crud_hook_test_entity_insert(EntityInterface $entity) { } /** - * Implements hook_block_insert(). + * Implements hook_ENTITY_TYPE_insert() for block entities. */ function entity_crud_hook_test_block_insert() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_comment_insert(). + * Implements hook_ENTITY_TYPE_insert() for comment entities. */ function entity_crud_hook_test_comment_insert() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_file_insert(). + * Implements hook_ENTITY_TYPE_insert() for file entities. */ function entity_crud_hook_test_file_insert() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_node_insert(). + * Implements hook_ENTITY_TYPE_insert() for node entities. */ function entity_crud_hook_test_node_insert() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_taxonomy_term_insert(). + * Implements hook_ENTITY_TYPE_insert() for taxonomy_term entities. */ function entity_crud_hook_test_taxonomy_term_insert() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_taxonomy_vocabulary_insert(). + * Implements hook_ENTITY_TYPE_insert() for taxonomy_vocabulary entities. */ function entity_crud_hook_test_taxonomy_vocabulary_insert() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_user_insert(). + * Implements hook_ENTITY_TYPE_insert() for user entities. */ function entity_crud_hook_test_user_insert() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); @@ -183,49 +183,49 @@ function entity_crud_hook_test_entity_load(array $entities, $type) { } /** - * Implements hook_block_load(). + * Implements hook_ENTITY_TYPE_load() for block entities. */ function entity_crud_hook_test_block_load() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_comment_load(). + * Implements hook_ENTITY_TYPE_load() for comment entities. */ function entity_crud_hook_test_comment_load() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_file_load(). + * Implements hook_ENTITY_TYPE_load() for file entities. */ function entity_crud_hook_test_file_load() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_node_load(). + * Implements hook_ENTITY_TYPE_load() for node entities. */ function entity_crud_hook_test_node_load() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_taxonomy_term_load(). + * Implements hook_ENTITY_TYPE_load() for taxonomy_term entities. */ function entity_crud_hook_test_taxonomy_term_load() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_taxonomy_vocabulary_load(). + * Implements hook_ENTITY_TYPE_load() for taxonomy_vocabulary entities. */ function entity_crud_hook_test_taxonomy_vocabulary_load() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_user_load(). + * Implements hook_ENTITY_TYPE_load() for user entities. */ function entity_crud_hook_test_user_load() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); @@ -239,49 +239,49 @@ function entity_crud_hook_test_entity_update(EntityInterface $entity) { } /** - * Implements hook_block_update(). + * Implements hook_ENTITY_TYPE_update() for block entities. */ function entity_crud_hook_test_block_update() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_comment_update(). + * Implements hook_ENTITY_TYPE_update() for comment entities. */ function entity_crud_hook_test_comment_update() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_file_update(). + * Implements hook_ENTITY_TYPE_update() for file entities. */ function entity_crud_hook_test_file_update() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_node_update(). + * Implements hook_ENTITY_TYPE_update() for node entities. */ function entity_crud_hook_test_node_update() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_taxonomy_term_update(). + * Implements hook_ENTITY_TYPE_update() for taxonomy_term entities. */ function entity_crud_hook_test_taxonomy_term_update() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_taxonomy_vocabulary_update(). + * Implements hook_ENTITY_TYPE_update() for taxonomy_vocabulary entities. */ function entity_crud_hook_test_taxonomy_vocabulary_update() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_user_update(). + * Implements hook_ENTITY_TYPE_update() for user entities. */ function entity_crud_hook_test_user_update() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); @@ -295,49 +295,49 @@ function entity_crud_hook_test_entity_predelete(EntityInterface $entity) { } /** - * Implements hook_block_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for block entities. */ function entity_crud_hook_test_block_predelete() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_comment_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for comment entities. */ function entity_crud_hook_test_comment_predelete() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_file_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for file entities. */ function entity_crud_hook_test_file_predelete() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_node_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for node entities. */ function entity_crud_hook_test_node_predelete() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_taxonomy_term_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for taxonomy_term entities. */ function entity_crud_hook_test_taxonomy_term_predelete() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_taxonomy_vocabulary_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for taxonomy_vocabulary entities. */ function entity_crud_hook_test_taxonomy_vocabulary_predelete() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_user_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for user entities. */ function entity_crud_hook_test_user_predelete() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); @@ -351,49 +351,49 @@ function entity_crud_hook_test_entity_delete(EntityInterface $entity) { } /** - * Implements hook_block_delete(). + * Implements hook_ENTITY_TYPE_delete() for block entities. */ function entity_crud_hook_test_block_delete() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_comment_delete(). + * Implements hook_ENTITY_TYPE_delete() for comment entities. */ function entity_crud_hook_test_comment_delete() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_file_delete(). + * Implements hook_ENTITY_TYPE_delete() for file entities. */ function entity_crud_hook_test_file_delete() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_node_delete(). + * Implements hook_ENTITY_TYPE_delete() for node entities. */ function entity_crud_hook_test_node_delete() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_taxonomy_term_delete(). + * Implements hook_ENTITY_TYPE_delete() for taxonomy_term entities. */ function entity_crud_hook_test_taxonomy_term_delete() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_taxonomy_vocabulary_delete(). + * Implements hook_ENTITY_TYPE_delete() for taxonomy_vocabulary entities. */ function entity_crud_hook_test_taxonomy_vocabulary_delete() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } /** - * Implements hook_user_delete(). + * Implements hook_ENTITY_TYPE_delete() for user entities. */ function entity_crud_hook_test_user_delete() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); diff --git a/core/modules/system/tests/modules/menu_test/menu_test.module b/core/modules/system/tests/modules/menu_test/menu_test.module index 9f1d06d26885..c222ce805b1a 100644 --- a/core/modules/system/tests/modules/menu_test/menu_test.module +++ b/core/modules/system/tests/modules/menu_test/menu_test.module @@ -167,21 +167,21 @@ function menu_test_menu_name($new_name = '') { } /** - * Implements hook_menu_link_insert(). + * Implements hook_ENTITY_TYPE_insert() for menu_link entities. */ function menu_test_menu_link_insert(MenuLink $item) { menu_test_static_variable('insert'); } /** - * Implements hook_menu_link_update(). + * Implements hook_ENTITY_TYPE_update() for menu_link entities. */ function menu_test_menu_link_update(MenuLink $item) { menu_test_static_variable('update'); } /** - * Implements hook_menu_link_delete(). + * Implements hook_ENTITY_TYPE_delete() for menu_link entities. */ function menu_test_menu_link_delete(MenuLink $item) { menu_test_static_variable('delete'); diff --git a/core/modules/taxonomy/taxonomy.api.php b/core/modules/taxonomy/taxonomy.api.php deleted file mode 100644 index 9fa84c1db2bd..000000000000 --- a/core/modules/taxonomy/taxonomy.api.php +++ /dev/null @@ -1,310 +0,0 @@ -<?php - -use Drupal\Core\Entity\EntityInterface; - -/** - * @file - * Hooks provided by the Taxonomy module. - */ - -/** - * @addtogroup hooks - * @{ - */ - -/** - * Act on a newly created vocabulary. - * - * This hook runs after a new vocabulary object has just been instantiated. It - * can be used to set initial values, e.g. to provide defaults. - * - * @param \Drupal\taxonomy\Entity\Vocabulary $vocabulary - * The vocabulary object. - */ -function hook_taxonomy_vocabulary_create(\Drupal\taxonomy\Entity\Vocabulary $vocabulary) { - if (!isset($vocabulary->foo)) { - $vocabulary->foo = NULL; - } -} - -/** - * Act on taxonomy vocabularies when loaded. - * - * Modules implementing this hook can act on the vocabulary objects before they - * are returned by entity_load_multiple(). - * - * @param array $vocabularies - * An array of taxonomy vocabulary entities. - */ -function hook_taxonomy_vocabulary_load(array $vocabularies) { - $result = db_select('mytable', 'm') - ->fields('m', array('vid', 'foo')) - ->condition('m.vid', array_keys($vocabularies), 'IN') - ->execute(); - foreach ($result as $record) { - $vocabularies[$record->vid]->foo = $record->foo; - } -} - -/** - * Act on taxonomy vocabularies before they are saved. - * - * Modules implementing this hook can act on the vocabulary object before it is - * inserted or updated. - * - * @param \Drupal\taxonomy\Entity\Vocabulary $vocabulary - * A taxonomy vocabulary entity. - */ -function hook_taxonomy_vocabulary_presave(Drupal\taxonomy\Entity\Vocabulary $vocabulary) { - $vocabulary->foo = 'bar'; -} - -/** - * Act on taxonomy vocabularies when inserted. - * - * Modules implementing this hook can act on the vocabulary object when saved - * to the database. - * - * @param \Drupal\taxonomy\Entity\Vocabulary $vocabulary - * A taxonomy vocabulary entity. - */ -function hook_taxonomy_vocabulary_insert(Drupal\taxonomy\Entity\Vocabulary $vocabulary) { - if ($vocabulary->id() == 'my_vocabulary') { - $vocabulary->weight = 100; - } -} - -/** - * Act on taxonomy vocabularies when updated. - * - * Modules implementing this hook can act on the vocabulary object when updated. - * - * @param \Drupal\taxonomy\Entity\Vocabulary $vocabulary - * A taxonomy vocabulary entity. - */ -function hook_taxonomy_vocabulary_update(Drupal\taxonomy\Entity\Vocabulary $vocabulary) { - db_update('mytable') - ->fields(array('foo' => $vocabulary->foo)) - ->condition('vid', $vocabulary->id()) - ->execute(); -} - -/** - * Act before taxonomy vocabulary deletion. - * - * This hook is invoked before entity_bundle_delete() is called and before - * the vocabulary is actually removed. - * - * @param \Drupal\taxonomy\Entity\Vocabulary $vocabulary - * The taxonomy vocabulary entity that is about to be deleted. - * - * @see hook_taxonomy_vocabulary_delete() - */ -function hook_taxonomy_vocabulary_predelete(Drupal\taxonomy\Entity\Vocabulary $vocabulary) { - db_delete('mytable_index') - ->condition('vid', $vocabulary->id()) - ->execute(); -} - -/** - * Respond to taxonomy vocabulary deletion. - * - * This hook is invoked after entity_bundle_delete() has been called and after - * the vocabulary has been removed. - * - * @param \Drupal\taxonomy\Entity\Vocabulary $vocabulary - * The taxonomy vocabulary entity that has been deleted. - * - * @see hook_taxonomy_vocabulary_predelete() - */ -function hook_taxonomy_vocabulary_delete(Drupal\taxonomy\Entity\Vocabulary $vocabulary) { - db_delete('mytable') - ->condition('vid', $vocabulary->id()) - ->execute(); -} - -/** - * Act on a newly created term. - * - * This hook runs after a new term object has just been instantiated. It can be - * used to set initial values, e.g. to provide defaults. - * - * @param \Drupal\taxonomy\Entity\Term $term - * The term object. - */ -function hook_taxonomy_term_create(\Drupal\taxonomy\Entity\Term $term) { - if (!isset($term->foo)) { - $term->foo = 'some_initial_value'; - } -} - -/** - * Act on taxonomy terms when loaded. - * - * Modules implementing this hook can act on the term objects returned by - * entity_load_multiple(). - * - * For performance reasons, information to be added to term objects should be - * loaded in a single query for all terms where possible. - * - * Since terms are stored and retrieved from cache during a page request, avoid - * altering properties provided by the {taxonomy_term_data} table, since this - * may affect the way results are loaded from cache in subsequent calls. - * - * @param array $terms - * An array of taxonomy term entities, indexed by tid. - */ -function hook_taxonomy_term_load(array $terms) { - $result = db_select('mytable', 'm') - ->fields('m', array('tid', 'foo')) - ->condition('m.tid', array_keys($terms), 'IN') - ->execute(); - foreach ($result as $record) { - $terms[$record->tid]->foo = $record->foo; - } -} - -/** - * Act on taxonomy terms before they are saved. - * - * Modules implementing this hook can act on the term object before it is - * inserted or updated. - * - * @param \Drupal\taxonomy\Term $term - * A taxonomy term entity. - */ -function hook_taxonomy_term_presave(Drupal\taxonomy\Term $term) { - $term->foo = 'bar'; -} - -/** - * Act on taxonomy terms when inserted. - * - * Modules implementing this hook can act on the term object when saved to - * the database. - * - * @param \Drupal\taxonomy\Term $term - * A taxonomy term entity. - */ -function hook_taxonomy_term_insert(Drupal\taxonomy\Term $term) { - db_insert('mytable') - ->fields(array( - 'tid' => $term->id(), - 'foo' => $term->foo, - )) - ->execute(); -} - -/** - * Act on taxonomy terms when updated. - * - * Modules implementing this hook can act on the term object when updated. - * - * @param \Drupal\taxonomy\Term $term - * A taxonomy term entity. - */ -function hook_taxonomy_term_update(Drupal\taxonomy\Term $term) { - db_update('mytable') - ->fields(array('foo' => $term->foo)) - ->condition('tid', $term->id()) - ->execute(); -} - -/** - * Act before taxonomy term deletion. - * - * This hook is invoked from taxonomy term deletion before field values are - * deleted and before the term is actually removed from the database. - * - * @param \Drupal\taxonomy\Term $term - * The taxonomy term entity that is about to be deleted. - */ -function hook_taxonomy_term_predelete(Drupal\taxonomy\Term $term) { - db_delete('mytable_index') - ->condition('tid', $term->id()) - ->execute(); -} - -/** - * Respond to taxonomy term deletion. - * - * This hook is invoked from taxonomy term deletion after field values are - * deleted and after the term has been removed from the database. - * - * @param \Drupal\taxonomy\Term $term - * The taxonomy term entity that has been deleted. - */ -function hook_taxonomy_term_delete(Drupal\taxonomy\Term $term) { - db_delete('mytable') - ->condition('tid', $term->id()) - ->execute(); -} - -/** - * Act on a taxonomy term that is being assembled before rendering. - * - * The module may add elements to a taxonomy term's renderable array array prior - * to rendering. - - * @param array &$build - * A renderable array representing the taxonomy term content. - * @param \Drupal\taxonomy\Entity\Term $term - * The term that is being assembled for rendering. - * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display - * The entity view display holding the display options configured for the term - * components. - * @param $view_mode - * The $view_mode parameter from taxonomy_term_view(). - * @param $langcode - * The language code used for rendering. - * - * @see hook_entity_view() - */ -function hook_taxonomy_term_view(array &$build, \Drupal\taxonomy\Entity\Term $term, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode, $langcode) { - // Only do the extra work if the component is configured to be displayed. - // This assumes a 'mymodule_addition' extra field has been defined for the - // vocabulary in hook_entity_extra_field_info(). - if ($display->getComponent('mymodule_addition')) { - $build['mymodule_addition'] = array( - '#markup' => mymodule_addition($term), - '#theme' => 'mymodule_my_additional_field', - ); - } -} - -/** - * Alter the results of taxonomy_term_view(). - * - * This hook is called after the content has been assembled in a structured - * array and may be used for doing processing which requires that the complete - * taxonomy term content structure has been built. - * - * If the module wishes to act on the rendered HTML of the term rather than the - * structured content array, it may use this hook to add a #post_render - * callback. Alternatively, it could also implement - * hook_preprocess_HOOK() for taxonomy-term.html.twig. See drupal_render() and - * _theme() documentation respectively for details. - * - * @param array &$build - * A renderable array representing the taxonomy term content. - * @param \Drupal\taxonomy\Entity\Term $term - * The taxonomy term being rendered. - * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display - * The entity view display holding the display options configured for the term - * components. - * - * @see hook_entity_view_alter() - */ -function hook_taxonomy_term_view_alter(array &$build, \Drupal\taxonomy\Entity\Term $term, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) { - if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) { - // Change its weight. - $build['an_additional_field']['#weight'] = -10; - } - - // Add a #post_render callback to act on the rendered HTML of the term. - $build['#post_render'][] = 'my_module_taxonomy_term_post_render'; -} - -/** - * @} End of "addtogroup hooks". - */ diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module index 0d9d7370cefb..56ec5149c5ae 100644 --- a/core/modules/taxonomy/taxonomy.module +++ b/core/modules/taxonomy/taxonomy.module @@ -746,7 +746,7 @@ function taxonomy_autocomplete_validate($element, &$form_state) { */ /** - * Implements hook_node_insert(). + * Implements hook_ENTITY_TYPE_insert() for node entities. */ function taxonomy_node_insert(EntityInterface $node) { // Add taxonomy index entries for the node. @@ -800,7 +800,7 @@ function taxonomy_build_node_index($node) { } /** - * Implements hook_node_update(). + * Implements hook_ENTITY_TYPE_update() for node entities. */ function taxonomy_node_update(EntityInterface $node) { // Always rebuild the node's taxonomy index entries on node save. @@ -809,7 +809,7 @@ function taxonomy_node_update(EntityInterface $node) { } /** - * Implements hook_node_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for node entities. */ function taxonomy_node_predelete(EntityInterface $node) { // Clean up the {taxonomy_index} table when nodes are deleted. @@ -829,7 +829,7 @@ function taxonomy_delete_node_index(EntityInterface $node) { } /** - * Implements hook_taxonomy_term_delete(). + * Implements hook_ENTITY_TYPE_delete() for taxonomy_term entities. */ function taxonomy_taxonomy_term_delete(Term $term) { if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) { diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module index a8b4f0815c96..83917807c614 100644 --- a/core/modules/toolbar/toolbar.module +++ b/core/modules/toolbar/toolbar.module @@ -541,7 +541,7 @@ function toolbar_modules_uninstalled($modules) { } /** - * Implements hook_ENTITY_TYPE_update(). + * Implements hook_ENTITY_TYPE_update() for menu_link entities. */ function toolbar_menu_link_update(MenuLinkInterface $menu_link) { if ($menu_link->menu_name === 'admin') { @@ -550,14 +550,14 @@ function toolbar_menu_link_update(MenuLinkInterface $menu_link) { } /** - * Implements hook_ENTITY_TYPE_update(). + * Implements hook_ENTITY_TYPE_update() for user entities. */ function toolbar_user_update(UserInterface $user) { _toolbar_clear_user_cache($user->id()); } /** - * Implements hook_ENTITY_TYPE_update(). + * Implements hook_ENTITY_TYPE_update() for user_role entities. */ function toolbar_user_role_update(RoleInterface $role) { _toolbar_clear_user_cache(); diff --git a/core/modules/tour/tour.api.php b/core/modules/tour/tour.api.php index 6537cc7c19ac..04049f5c2daf 100644 --- a/core/modules/tour/tour.api.php +++ b/core/modules/tour/tour.api.php @@ -5,6 +5,11 @@ * Describes API functions for tour module. */ +/** + * @addtogroup hooks + * @{ + */ + /** * Allow modules to alter tour items before render. * @@ -37,52 +42,5 @@ function hook_tour_tips_info_alter(&$info) { } /** - * Act on tour objects when loaded. - * - * @param array $entities - * An array of \Drupal\tour\Entity\Tour objects, indexed by id. - */ -function hook_tour_load($entities) { - if (isset($entities['tour-entity-create-test-en'])) { - $entities['tour-entity-create-test-en']->loaded = 'Load hooks work'; - } -} - -/** - * Act on a tour being inserted or updated. - * - * This hook is invoked before the tour object is saved to configuration. - * - * @param \Drupal\tour\Entity\Tour $entity - * The tour object. - * - * @see hook_tour_insert() - * @see hook_tour_update() - */ -function hook_tour_presave($entity) { - if ($entity->id() == 'tour-entity-create-test-en') { - $entity->set('label', $entity->label() . ' alter'); - } -} - -/** - * Respond to creation of a new tour. - * - * @param \Drupal\tour\Entity\Tour $entity - * The tour object being inserted. - */ -function hook_tour_insert($entity) { - \Drupal::service('plugin.manager.tour.tip')->clearCachedDefinitions(); - \Drupal\Core\Cache\Cache::deleteTags(array('tour_items')); -} - -/** - * Respond to updates to a tour object. - * - * @param \Drupal\tour\Entity\Tour $entity - * The tour object being updated. + * @} End of "addtogroup hooks". */ -function hook_tour_update($entity) { - \Drupal::service('plugin.manager.tour.tip')->clearCachedDefinitions(); - \Drupal\Core\Cache\Cache::deleteTags(array('tour_items')); -} diff --git a/core/modules/tour/tour.module b/core/modules/tour/tour.module index 17001e8d34d4..001acaf7d9b4 100644 --- a/core/modules/tour/tour.module +++ b/core/modules/tour/tour.module @@ -103,14 +103,14 @@ function tour_preprocess_page(&$variables) { } /** - * Implements hook_tour_insert(). + * Implements hook_ENTITY_TYPE_insert() for tour entities. */ function tour_tour_insert($entity) { \Drupal::service('plugin.manager.tour.tip')->clearCachedDefinitions(); } /** - * Implements hook_tour_update(). + * Implements hook_ENTITY_TYPE_update() for tour entities. */ function tour_tour_update($entity) { \Drupal::service('plugin.manager.tour.tip')->clearCachedDefinitions(); diff --git a/core/modules/tracker/tracker.module b/core/modules/tracker/tracker.module index d1c911b33b72..1c41d50cd782 100644 --- a/core/modules/tracker/tracker.module +++ b/core/modules/tracker/tracker.module @@ -154,7 +154,7 @@ function _tracker_user_access($account) { } /** - * Implements hook_node_insert(). + * Implements hook_ENTITY_TYPE_insert() for node entities. * * Adds new tracking information for this node since it's new. */ @@ -163,7 +163,7 @@ function tracker_node_insert(NodeInterface $node, $arg = 0) { } /** - * Implements hook_node_update(). + * Implements hook_ENTITY_TYPE_update() for node entities. * * Adds tracking information for this node since it's been updated. */ @@ -172,7 +172,7 @@ function tracker_node_update(NodeInterface $node, $arg = 0) { } /** - * Implements hook_node_predelete(). + * Implements hook_ENTITY_TYPE_predelete() for node entities. * * Deletes tracking information for a node. */ @@ -186,7 +186,7 @@ function tracker_node_predelete(EntityInterface $node, $arg = 0) { } /** - * Implements hook_comment_update(). + * Implements hook_ENTITY_TYPE_update() for comment entities. */ function tracker_comment_update(CommentInterface $comment) { if ($comment->getCommentedEntityTypeId() == 'node') { @@ -200,7 +200,7 @@ function tracker_comment_update(CommentInterface $comment) { } /** - * Implements hook_comment_insert(). + * Implements hook_ENTITY_TYPE_insert() for comment entities. */ function tracker_comment_insert(CommentInterface $comment) { if ($comment->getCommentedEntityTypeId() == 'node' && $comment->isPublished()) { @@ -209,7 +209,7 @@ function tracker_comment_insert(CommentInterface $comment) { } /** - * Implements hook_comment_delete(). + * Implements hook_ENTITY_TYPE_delete() for comment entities. */ function tracker_comment_delete(CommentInterface $comment) { if ($comment->getCommentedEntityTypeId() == 'node') { diff --git a/core/modules/user/user.api.php b/core/modules/user/user.api.php index 7b5313eb4dab..34e9f7f06fb0 100644 --- a/core/modules/user/user.api.php +++ b/core/modules/user/user.api.php @@ -12,81 +12,6 @@ * @{ */ -/** - * Act on a newly created user. - * - * This hook runs after a new user object has just been instantiated. It can be - * used to set initial values, e.g. to provide defaults. - * - * @param \Drupal\user\UserInterface $user - * The user object. - */ -function hook_user_create(\Drupal\user\Entity\User $user) { - if (!isset($user->foo)) { - $user->foo = 'some_initial_value'; - } -} - -/** - * Act on user objects when loaded from the database. - * - * Due to the static cache in user_load_multiple() you should not use this - * hook to modify the user properties returned by the {users} table itself - * since this may result in unreliable results when loading from cache. - * - * @param $users - * An array of user objects, indexed by uid. - * - * @see user_load_multiple() - * @see profile_user_load() - */ -function hook_user_load($users) { - $result = db_query('SELECT uid, foo FROM {my_table} WHERE uid IN (:uids)', array(':uids' => array_keys($users))); - foreach ($result as $record) { - $users[$record->uid]->foo = $record->foo; - } -} - -/** - * Act before user deletion. - * - * This hook is invoked from user_delete_multiple() before field values are - * deleted and before the user is actually removed from the database. - * - * Modules should additionally implement hook_user_cancel() to process stored - * user data for other account cancellation methods. - * - * @param $account - * The account that is about to be deleted. - * - * @see hook_user_delete() - * @see user_delete_multiple() - */ -function hook_user_predelete($account) { - db_delete('mytable') - ->condition('uid', $account->id()) - ->execute(); -} - -/** - * Respond to user deletion. - * - * This hook is invoked from user_delete_multiple() after field values are - * deleted and after the user has been removed from the database. - * - * Modules should additionally implement hook_user_cancel() to process stored - * user data for other account cancellation methods. - * - * @param $account - * The account that has been deleted. - * - * @see hook_user_predelete() - * @see user_delete_multiple() - */ -function hook_user_delete($account) { - drupal_set_message(t('User: @name has been deleted.', array('@name' => $account->getUsername()))); -} - /** * Act on user account cancellations. * @@ -97,8 +22,8 @@ function hook_user_delete($account) { * Modules may add further methods via hook_user_cancel_methods_alter(). * * This hook is NOT invoked for the 'user_cancel_delete' account cancellation - * method. To react to that method, implement hook_user_predelete() or - * hook_user_delete() instead. + * method. To react to that method, implement hook_ENTITY_TYPE_predelete() or + * hook_ENTITY_TYPE_delete() for user entities instead. * * Expensive operations should be added to the global account cancellation batch * by using batch_set(). @@ -201,78 +126,6 @@ function hook_user_format_name_alter(&$name, $account) { } } -/** - * Act on a user account being inserted or updated. - * - * This hook is invoked before the user account is saved to the database. - * - * @param $account - * The user account object. - * - * @see hook_user_insert() - * @see hook_user_update() - */ -function hook_user_presave($account) { - // Ensure that our value is an array. - if (isset($account->mymodule_foo)) { - $account->mymodule_foo = (array) $account->mymodule_foo; - } -} - -/** - * Respond to creation of a new user account. - * - * Note that when this hook is invoked, the changes have not yet been written to - * the database, because a database transaction is still in progress. The - * transaction is not finalized until the insert operation is entirely completed - * and \Drupal\user\DataStorage::save() goes out of scope. You should - * not rely on data in the database at this time as it is not updated yet. You - * should also note that any write/update database queries executed from this hook - * are also not committed immediately. Check \Drupal\user\DataStorage::save() - * and db_transaction() for more info. - * - * @param $account - * The user account object. - * - * @see hook_user_presave() - * @see hook_user_update() - */ -function hook_user_insert($account) { - db_insert('user_changes') - ->fields(array( - 'uid' => $account->id(), - 'created' => time(), - )) - ->execute(); -} - -/** - * Respond to updates to a user account. - * - * Note that when this hook is invoked, the changes have not yet been written to - * the database, because a database transaction is still in progress. The - * transaction is not finalized until the update operation is entirely completed - * and \Drupal\user\DataStorage::save() goes out of scope. You should not - * rely on data in the database at this time as it is not updated yet. You should - * also note that any write/update database queries executed from this hook are - * also not committed immediately. Check \Drupal\user\DataStorage::save() - * and db_transaction() for more info. - * - * @param $account - * The user account object. - * - * @see hook_user_presave() - * @see hook_user_insert() - */ -function hook_user_update($account) { - db_insert('user_changes') - ->fields(array( - 'uid' => $account->id(), - 'changed' => time(), - )) - ->execute(); -} - /** * The user just logged in. * @@ -302,153 +155,6 @@ function hook_user_logout($account) { ->execute(); } -/** - * The user's account information is being displayed. - * - * The module should format its custom additions for display and add them to the - * $build array. - * - * @param array &$build - * A renderable array representing the user content. - * @param \Drupal\user\UserInterface $account - * The user object on which the operation is being performed. - * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display - * The entity view display holding the display options configured for the user - * components. - * @param $view_mode - * View mode, e.g. 'full'. - * @param $langcode - * The language code used for rendering. - * - * @see hook_user_view_alter() - * @see hook_entity_view() - */ -function hook_user_view(array &$build, \Drupal\user\UserInterface $account, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode, $langcode) { - // Only do the extra work if the component is configured to be displayed. - // This assumes a 'mymodule_addition' extra field has been defined for the - // user entity type in hook_entity_extra_field_info(). - if ($display->getComponent('mymodule_addition')) { - $build['mymodule_addition'] = array( - '#markup' => mymodule_addition($account), - '#theme' => 'mymodule_my_additional_field', - ); - } -} - -/** - * The user was built; the module may modify the structured content. - * - * This hook is called after the content has been assembled in a structured array - * and may be used for doing processing which requires that the complete user - * content structure has been built. - * - * If the module wishes to act on the rendered HTML of the user rather than the - * structured content array, it may use this hook to add a #post_render callback. - * Alternatively, it could also implement hook_preprocess_HOOK() for - * user.html.twig. See drupal_render() and _theme() documentation - * respectively for details. - * - * @param array &$build - * A renderable array representing the user. - * @param \Drupal\user\UserInterface $account - * The user account being rendered. - * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display - * The entity view display holding the display options configured for the user - * components. - * - * @see user_view() - * @see hook_entity_view_alter() - */ -function hook_user_view_alter(array &$build, \Drupal\user\UserInterface $account, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) { - // Check for the existence of a field added by another module. - if (isset($build['an_additional_field'])) { - // Change its weight. - $build['an_additional_field']['#weight'] = -10; - } - - // Add a #post_render callback to act on the rendered HTML of the user. - $build['#post_render'][] = 'my_module_user_post_render'; -} - -/** - * Act on a user role being inserted or updated. - * - * Modules implementing this hook can act on the user role object before - * it has been saved to the database. - * - * @param $role - * A user role object. - * - * @see hook_user_role_insert() - * @see hook_user_role_update() - */ -function hook_user_role_presave($role) { - // Set a UUID for the user role if it doesn't already exist - if (empty($role->uuid)) { - $role->uuid = uuid_uuid(); - } -} - -/** - * Respond to creation of a new user role. - * - * Modules implementing this hook can act on the user role object when saved to - * the database. It's recommended that you implement this hook if your module - * adds additional data to user roles object. The module should save its custom - * additions to the database. - * - * @param $role - * A user role object. - */ -function hook_user_role_insert($role) { - // Save extra fields provided by the module to user roles. - db_insert('my_module_table') - ->fields(array( - 'rid' => $role->id(), - 'role_description' => $role->description, - )) - ->execute(); -} - -/** - * Respond to updates to a user role. - * - * Modules implementing this hook can act on the user role object when updated. - * It's recommended that you implement this hook if your module adds additional - * data to user roles object. The module should save its custom additions to - * the database. - * - * @param $role - * A user role object. - */ -function hook_user_role_update($role) { - // Save extra fields provided by the module to user roles. - db_merge('my_module_table') - ->key('rid', $role->id()) - ->fields(array( - 'role_description' => $role->description - )) - ->execute(); -} - -/** - * Respond to user role deletion. - * - * This hook allows you act when a user role has been deleted. - * If your module stores references to roles, it's recommended that you - * implement this hook and delete existing instances of the deleted role - * in your module database tables. - * - * @param $role - * The $role object being deleted. - */ -function hook_user_role_delete($role) { - // Delete existing instances of the deleted role. - db_delete('my_module_table') - ->condition('rid', $role->id()) - ->execute(); -} - /** * @} End of "addtogroup hooks". */ diff --git a/core/modules/user/user.module b/core/modules/user/user.module index 78d879cb0946..3e84dd6dcbe1 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -494,7 +494,7 @@ function user_permission() { } /** - * Implements hook_user_view(). + * Implements hook_ENTITY_TYPE_view() for user entities. */ function user_user_view(array &$build, UserInterface $account, EntityViewDisplayInterface $display) { if ($display->getComponent('member_for')) { @@ -736,8 +736,9 @@ function user_login_finalize(UserInterface $account) { ->updateLastLoginTimestamp($account); // Regenerate the session ID to prevent against session fixation attacks. - // This is called before hook_user in case one of those functions fails - // or incorrectly does a redirect which would leave the old session in place. + // This is called before hook_user_login() in case one of those functions + // fails or incorrectly does a redirect which would leave the old session + // in place. \Drupal::service('session_manager')->regenerate(); \Drupal::moduleHandler()->invokeAll('user_login', array($account)); @@ -871,8 +872,9 @@ function user_cancel($edit, $uid, $method) { batch_set($batch); // When the 'user_cancel_delete' method is used, user_delete() is called, - // which invokes hook_user_predelete() and hook_user_delete(). Modules - // should use those hooks to respond to the account deletion. + // which invokes hook_ENTITY_TYPE_predelete() and hook_ENTITY_TYPE_delete() + // for the user entity. Modules should use those hooks to respond to the + // account deletion. if ($method != 'user_cancel_delete') { // Allow modules to add further sets to this batch. \Drupal::moduleHandler()->invokeAll('user_cancel', array($edit, $account, $method)); @@ -1029,8 +1031,8 @@ function user_delete($uid) { * @param $uids * An array of user IDs. * - * @see hook_user_predelete() - * @see hook_user_delete() + * @see hook_ENTITY_TYPE_predelete() + * @see hook_ENTITY_TYPE_delete() */ function user_delete_multiple(array $uids) { entity_delete_multiple('user', $uids); @@ -1154,7 +1156,7 @@ function user_role_names($membersonly = FALSE, $permission = NULL) { } /** - * Implements hook_user_role_insert(). + * Implements hook_ENTITY_TYPE_insert() for user_role entities. */ function user_user_role_insert(RoleInterface $role) { // Ignore the authenticated and anonymous roles or the role is being synced. @@ -1191,7 +1193,7 @@ function user_user_role_insert(RoleInterface $role) { } /** - * Implements hook_user_role_delete(). + * Implements hook_ENTITY_TYPE_delete() for user_role entities. */ function user_user_role_delete(RoleInterface $role) { // Ignore the authenticated and anonymous roles or the role is being synced. -- GitLab