Skip to content
entity.api.php 74 KiB
Newer Older
 * Hooks and documentation related to entities.
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\DynamicallyFieldableEntityStorageInterface;
use Drupal\language\Entity\ContentLanguageSettings;
/**
 * @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\Sql\SqlContentEntityStorage 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_storage_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)
 *
 * @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->getId());
 * @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()
 * @}
 */

/**
 * @defgroup entity_api Entity API
 * @{
 * Describes how to define and manipulate content and configuration entities.
 *
 * Entities, in Drupal, are objects that are used for persistent storage of
 * content and configuration information. See the
 * @link info_types Information types topic @endlink for an overview of the
 * different types of information, and the
 * @link config_api Configuration API topic @endlink for more about the
 * configuration API.
 *
 * Each entity is an instance of a particular "entity type". Some content entity
 * types have sub-types, which are known as "bundles", while for other entity
 * types, there is only a single bundle. For example, the Node content entity
 * type, which is used for the main content pages in Drupal, has bundles that
 * are known as "content types", while the User content type, which is used for
 * user accounts, has only one bundle.
 *
 * The sections below have more information about entities and the Entity API;
 * for more detailed information, see https://drupal.org/developing/api/entity
 *
 * @section define Defining an entity type
 * Entity types are defined by modules, using Drupal's Plugin API (see the
 * @link plugin_api Plugin API topic @endlink for more information about plugins
 * in general). Here are the steps to follow to define a new entity type:
 * - Choose a unique machine name, or ID, for your entity type. This normally
 *   starts with (or is the same as) your module's machine name. It should be
 *   as short as possible, and may not exceed 32 characters.
 * - Define an interface for your entity's get/set methods, usually extending
 *   either \Drupal\Core\Config\Entity\ConfigEntityInterface or
 *   \Drupal\Core\Entity\ContentEntityInterface.
 * - Define a class for your entity, implementing your interface and extending
 *   either \Drupal\Core\Config\Entity\ConfigEntityBase or
 *   \Drupal\Core\Entity\ContentEntityBase, with annotation for
 *   \@ConfigEntityType or \@ContentEntityType in its documentation block.
 * - The 'id' annotation gives the entity type ID, and the 'label' annotation
 *   gives the human-readable name of the entity type. If you are defining a
 *   content entity type that uses bundles, the 'bundle_label' annotation gives
 *   the human-readable name to use for a bundle of this entity type (for
 *   example, "Content type" for the Node entity).
 * - The annotation will refer to several controller classes, which you will
 *   also need to define:
 *   - list_builder: Define a class that extends
 *     \Drupal\Core\Config\Entity\ConfigEntityListBuilder (for configuration
 *     entities) or \Drupal\Core\Entity\EntityListBuilder (for content
 *     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 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_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
 *     the content. Configuration translation is handled automatically by the
 *     Configuration Translation module, without the need of a controller class.
 *   - access: If your configuration entity has complex permissions, you might
 *     need an access control handling, implementing
 *     \Drupal\Core\Entity\EntityAccessControlHandlerInterface, but most entities
 *     can just use the 'admin_permission' annotation instead. Note that if you
 *     are creating your own access control handler, 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\Sql\SqlContentEntityStorage, and
 *     config entities will use \Drupal\Core\Config\Entity\ConfigEntityStorage.
 *     You can extend one of these classes to provide custom behavior.
 *   - views_data: A class implementing \Drupal\views\EntityViewsDataInterface
 *     to provide views data for the entity type. You can autogenerate most of
 *     the views data by extending \Drupal\views\EntityViewsData.
 * - 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
 *   \Drupal\Core\Entity\EntityType. Your module will also need to set up its
 *   database tables using hook_schema().
 * - For content entities that are displayed on their own pages, the annotation
 *   will refer to a 'uri_callback' function, which takes an object of the
 *   entity interface you have defined as its parameter, and returns routing
 *   information for the entity page; see node_uri() for an example. You will
 *   also need to add a corresponding route to your module's routing.yml file;
 *   see the entity.node.canonical route in node.routing.yml for an example, and see
 * - Define routes and links for the various URLs associated with the entity.
 *   These go into the 'links' annotation, with the link type as the key, and
 *   the path of this link template as the value. The corresponding route
 *   requires the following route name:
 *   "entity.$entity_type_id.$link_template_type". See @ref sec_routes below for
 *   some routing notes. Typical link types are:
 *   - canonical: Default link, either to view (if entities are viewed on their
 *     own pages) or edit the entity.
 *   - delete-form: Confirmation form to delete the entity.
 *   - edit-form: Editing form.
 *   - Other link types specific to your entity type can also be defined.
 * - If your content entity is fieldable, provide 'field_ui_base_route'
 *   annotation, giving the name of the route that the Manage Fields, Manage
 *   Display, and Manage Form Display pages from the Field UI module will be
 *   attached to. This is usually the bundle settings edit page, or an entity
 *   type settings page if there are no bundles.
 * - If your content entity has bundles, you will also need to define a second
 *   plugin to handle the bundles. This plugin is itself a configuration entity
 *   type, so follow the steps here to define it. The machine name ('id'
 *   annotation) of this configuration entity class goes into the
 *   '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. 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
 *   \Drupal\Core\Entity\EntityType.
 *
 * @section sec_routes Entity routes
 * Entity routes, like other routes, are defined in *.routing.yml files; see
 * the @link menu Menu and routing @endlink topic for more information. Here
 * is a typical entry, for the block configure form:
 * @code
 *   path: '/admin/structure/block/manage/{block}'
 *   defaults:
 *     _entity_form: 'block.default'
 *     _title: 'Configure block'
 *   requirements:
 *     _entity_access: 'block.update'
 * @endcode
 * Some notes:
 * - path: The {block} in the path is a placeholder, which (for an entity) must
 *   always take the form of {machine_name_of_entity_type}. In the URL, the
 *   placeholder value will be the ID of an entity item. When the route is used,
 *   the entity system will load the corresponding entity item and pass it in as
 *   an object to the controller for the route.
 * - defaults: For entity form routes, use _entity_form rather than the generic
 *   _controller or _form. The value is composed of the entity type machine name
 *   and a form controller type from the entity annotation (see @ref define
 *   above more more on controllers and annotation). So, in this example,
 *   block.default refers to the 'default' form controller on the block entity
 *   type, whose annotation contains:
 *   @code
 *     "form" = {
 *       "default" = "Drupal\block\BlockForm",
 *   @endcode
 *
 * @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:
 * @code
 * $storage = \Drupal::entityManager()->getStorage('your_entity_type');
 * // Or if you have a $container variable:
 * $storage = $container->get('entity.manager')->getStorage('your_entity_type');
 * @endcode
 * Here, 'your_entity_type' is the machine name of your entity type ('id'
 * annotation on the entity class), and note that you should use dependency
 * injection to retrieve this object if possible. See the
 * @link container Services and Dependency Injection topic @endlink for more
 * about how to properly retrieve services.
 *
 * To query to find entities to load, use an entity query, which is a object
 * implementing \Drupal\Core\Entity\Query\QueryInterface that you can retrieve
 * with:
 * @code
 * // Simple query:
 * $query = \Drupal::entityQuery('your_entity_type');
 * // Or, if you have a $container variable:
 * $query_service = $container->get('entity.query');
 * $query = $query_service->get('your_entity_type');
 * @endcode
 * If you need aggregation, there is an aggregate query available, which
 * implements \Drupal\Core\Entity\Query\QueryAggregateInterface:
 * @code
 * $query \Drupal::entityQueryAggregate('your_entity_type');
 * // Or:
 * $query = $query_service->getAggregate('your_entity_type');
 * @endcode
 * Also, you should use dependency injection to get this object if
 * possible; the service you need is entity.query, and its methods getQuery()
 * or getAggregateQuery() will get the query object.
 *
 * In either case, you can then add conditions to your query, using methods
 * like condition(), exists(), etc. on $query; add sorting, pager, and range
 * if needed, and execute the query to return a list of entity IDs that match
 * the query.
 *
 * Here is an example, using the core File entity:
 * @code
 * $fids = Drupal::entityQuery('file')
 *   ->condition('status', FILE_STATUS_PERMANENT, '<>')
 *   ->condition('changed', REQUEST_TIME - $age, '<')
 *   ->range(0, 100)
 *   ->execute();
 * $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->getId());
 * // $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
 * particular permission scheme. Instead, once you have an entity object
 * loaded, you can check for permission for a particular operation (such as
 * 'view') at the entity or field level by calling:
 * @code
 * $entity->access($operation);
 * $entity->nameOfField->access($operation);
 * @endcode
 * The interface related to access checking in entities and fields is
 * \Drupal\Core\Access\AccessibleInterface.
 *
 * The default entity access control handler 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.
 *
 * 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
 *
 * @see i18n
 * @see entity_crud
 * @}
 */

/**
 * Control entity operation access.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   The entity to check access to.
 * @param string $operation
 *   The operation that is to be performed on $entity.
 * @param \Drupal\Core\Session\AccountInterface $account
 *    The account trying to access the entity.
 * @param string $langcode
 *    The code of the language $entity is accessed in.
 *
 * @return \Drupal\Core\Access\AccessResultInterface
 *    The access result.
 * @see \Drupal\Core\Entity\EntityAccessControlHandler
 * @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) {
}

/**
 * Control entity operation access for a specific entity type.
 *
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   The entity to check access to.
 * @param string $operation
 *   The operation that is to be performed on $entity.
 * @param \Drupal\Core\Session\AccountInterface $account
 *    The account trying to access the entity.
 * @param string $langcode
 *    The code of the language $entity is accessed in.
 *
 * @return \Drupal\Core\Access\AccessResultInterface
 *    The access result.
 * @see \Drupal\Core\Entity\EntityAccessControlHandler
 * @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) {
}

/**
 * Control entity create access.
 *
 * @param \Drupal\Core\Session\AccountInterface $account
 *    The account trying to access the entity.
 * @param array $context
 *    An associative array of additional context values. By default it contains
 *    language:
 *    - langcode - the current language code.
 * @param string $entity_bundle
 *    The entity bundle name.
 * @return \Drupal\Core\Access\AccessResultInterface
 *    The access result.
 * @see \Drupal\Core\Entity\EntityAccessControlHandler
 * @see hook_entity_access()
 * @see hook_ENTITY_TYPE_create_access()
 *
 * @ingroup entity_api
function hook_entity_create_access(\Drupal\Core\Session\AccountInterface $account, array $context, $entity_bundle) {
}

/**
 * Control entity create access for a specific entity type.
 *
 * @param \Drupal\Core\Session\AccountInterface $account
 *    The account trying to access the entity.
 * @param array $context
 *    An associative array of additional context values. By default it contains
 *    language:
 *    - langcode - the current language code.
 * @param string $entity_bundle
 *    The entity bundle name.
 * @return \Drupal\Core\Access\AccessResultInterface
 *    The access result.
 * @see \Drupal\Core\Entity\EntityAccessControlHandler
 * @see hook_ENTITY_TYPE_access()
 * @see hook_entity_create_access()
 *
 * @ingroup entity_api
function hook_ENTITY_TYPE_create_access(\Drupal\Core\Session\AccountInterface $account, array $context, $entity_bundle) {
 * Modules may implement this hook to add information to defined entity types,
 * as defined in \Drupal\Core\Entity\EntityTypeInterface.
 * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types
 *   An associative array of all entity type definitions, keyed by the entity
 *   type name. Passed by reference.
 *
 * @see \Drupal\Core\Entity\Entity
 * @see \Drupal\Core\Entity\EntityTypeInterface
function hook_entity_type_build(array &$entity_types) {
  /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
  // Add a form for a custom node form without overriding the default
  // node form. To override the default node form, use hook_entity_type_alter().
  $entity_types['node']->setFormClass('mymodule_foo', 'Drupal\mymodule\NodeFooForm');
/**
 * Alter the entity type definitions.
 *
 * Modules may implement this hook to alter the information that defines an
 * entity type. All properties that are available in
 * \Drupal\Core\Entity\Annotation\EntityType and all the ones additionally
 * provided by modules can be altered here.
 *
 * Do not use this hook to add information to entity types, unless you are just
 * filling-in default values. Use hook_entity_type_build() instead.
 * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types
 *   An associative array of all entity type definitions, keyed by the entity
 *   type name. Passed by reference.
 *
 * @see \Drupal\Core\Entity\Entity
 * @see \Drupal\Core\Entity\EntityTypeInterface
 */
function hook_entity_type_alter(array &$entity_types) {
  /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
  // Set the controller class for nodes to an alternate implementation of the
  // Drupal\Core\Entity\EntityStorageInterface interface.
  $entity_types['node']->setStorageClass('Drupal\mymodule\MyCustomNodeStorage');
/**
 * Alter the view modes for entity types.
 *
 * @param array $view_modes
 *   An array of view modes, keyed first by entity type, then by view mode name.
 *
 * @see \Drupal\Core\Entity\EntityManagerInterface::getAllViewModes()
 * @see \Drupal\Core\Entity\EntityManagerInterface::getViewModes()
 * @see hook_entity_view_mode_info()
 */
function hook_entity_view_mode_info_alter(&$view_modes) {
}

/**
 * Describe the bundles for entity types.
 *
 * @return array
 *   An associative array of all entity bundles, keyed by the entity
 *   type name, and then the bundle name, with the following keys:
 *   - label: The human-readable name of the bundle.
 *   - uri_callback: The same as the 'uri_callback' key defined for the entity
 *     type in the EntityManager, but for the bundle only. When determining
 *     the URI of an entity, if a 'uri_callback' is defined for both the
 *     entity type and the bundle, the one for the bundle is used.
 *   - translatable: (optional) A boolean value specifying whether this bundle
 *     has translation support enabled. Defaults to FALSE.
 *
 * @see entity_get_bundles()
 * @see hook_entity_bundle_info_alter()
 */
function hook_entity_bundle_info() {
  $bundles['user']['user']['label'] = t('User');
  return $bundles;
}

/**
 * Alter the bundles for entity types.
 *
 * @param array $bundles
 *   An array of bundles, keyed first by entity type, then by bundle name.
 *
 * @see entity_get_bundles()
 * @see hook_entity_bundle_info()
 */
function hook_entity_bundle_info_alter(&$bundles) {
  $bundles['user']['user']['label'] = t('Full account');
/**
 * Act on entity_bundle_create().
 *
 * This hook is invoked after the operation has been performed.
 *
 *   The type of $entity; e.g. 'node' or 'user'.
 * @param string $bundle
 *   The name of the bundle.
function hook_entity_bundle_create($entity_type_id, $bundle) {
  // When a new bundle is created, the menu needs to be rebuilt to add the
  // Field UI menu item tabs.
  \Drupal::service('router.builder')->setRebuildNeeded();
}

/**
 * Act on entity_bundle_rename().
 *
 * This hook is invoked after the operation has been performed.
 *
 *   The entity type to which the bundle is bound.
 * @param string $bundle_old
 *   The previous name of the bundle.
 * @param string $bundle_new
 *   The new name of the bundle.
function hook_entity_bundle_rename($entity_type_id, $bundle_old, $bundle_new) {
  // Update the settings associated with the bundle in my_module.settings.
  $config = \Drupal::config('my_module.settings');
  $bundle_settings = $config->get('bundle_settings');
  if (isset($bundle_settings[$entity_type_id][$bundle_old])) {
    $bundle_settings[$entity_type_id][$bundle_new] = $bundle_settings[$entity_type_id][$bundle_old];
    unset($bundle_settings[$entity_type_id][$bundle_old]);
    $config->set('bundle_settings', $bundle_settings);
  }
}

/**
 * Act on entity_bundle_delete().
 *
 * This hook is invoked after the operation has been performed.
 *
 *   The type of entity; for example, 'node' or 'user'.
 * @param string $bundle
 *   The bundle that was just deleted.
function hook_entity_bundle_delete($entity_type_id, $bundle) {
  // Remove the settings associated with the bundle in my_module.settings.
  $config = \Drupal::config('my_module.settings');
  $bundle_settings = $config->get('bundle_settings');
  if (isset($bundle_settings[$entity_type_id][$bundle])) {
    unset($bundle_settings[$entity_type_id][$bundle]);
/**
 * Act on a newly created entity.
 *
 * 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_TYPE_create()
 */
function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) {
  if ($entity instanceof FieldableEntityInterface && !$entity->foo->value) {
/**
 * 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.
 *
 * This is a generic load hook called for all entity types loaded via the
 * entity API.
 *
 * hook_entity_storage_load() should be used to load additional data for
 * content entities.
 *
 * @param \Drupal\Core\Entity\EntityInterface[] $entities
 *   The type of entities being loaded (i.e. node, user, comment).
 *
 * @ingroup entity_crud
 * @see hook_ENTITY_TYPE_load()
function hook_entity_load(array $entities, $entity_type_id) {
    $entity->foo = mymodule_add_something($entity);
 * 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 content entities when loaded from the storage.
 *
 * The results of this hook will be cached.
 *
 * @param \Drupal\Core\Entity\EntityInterface[] $entities
 *   The entities keyed by entity ID.
 * @param string $entity_type
 *   The type of entities being loaded (i.e. node, user, comment).
 *
 * @see hook_entity_load()
 */
function hook_entity_storage_load(array $entities, $entity_type) {
  foreach ($entities as $entity) {
    $entity->foo = mymodule_add_something_uncached($entity);
  }
}

/**
 * Act on content entities of a given type when loaded from the storage.
 *
 * The results of this hook will be cached if the entity type supports it.
 *
 * @param \Drupal\Core\Entity\EntityInterface[] $entities
 *   The entities keyed by entity ID.
 *
 * @see hook_entity_storage_load()
 */
function hook_ENTITY_TYPE_storage_load(array $entities) {
  foreach ($entities as $entity) {
    $entity->foo = mymodule_add_something_uncached($entity);
  }
}

/**
 * Act on an entity before it is created or updated.
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *
 * @ingroup entity_crud
 * @see hook_ENTITY_TYPE_presave()
function hook_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
 if ($entity instanceof ContentEntityInterface && $entity->isTranslatable()) {
   $route_match = \Drupal::routeMatch();
   \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->getId(), $route_match->getParameter('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()) {
    $route_match = \Drupal::routeMatch();
    \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->getId(), $route_match->getParameter('source_langcode'));
 * Respond to creation of a new entity.
 *
 * 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
 *
 * @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.
  db_insert('example_entity')
    ->fields(array(
      'type' => $entity->getEntityTypeId(),
      'created' => REQUEST_TIME,
      'updated' => REQUEST_TIME,
    ))
    ->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.
 *
 * 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
 *
 * @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.
  db_update('example_entity')
    ->fields(array(
      'updated' => REQUEST_TIME,
    ))
    ->condition('type', $entity->getEntityTypeId())
/**
 * 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(