1<?php
2
3/**
4 * @file
5 * Hooks and documentation related to entities.
6 */
7
8use Drupal\Core\Access\AccessResult;
9use Drupal\Core\Entity\ContentEntityInterface;
10use Drupal\Core\Entity\DynamicallyFieldableEntityStorageInterface;
11use Drupal\Core\Field\BaseFieldDefinition;
12use Drupal\Core\Field\FieldDefinition;
13use Drupal\Core\Render\Element;
14use Drupal\language\Entity\ContentLanguageSettings;
15use Drupal\node\Entity\NodeType;
16
17/**
18 * @defgroup entity_crud Entity CRUD, editing, and view hooks
19 * @{
20 * Hooks used in various entity operations.
21 *
22 * Entity create, read, update, and delete (CRUD) operations are performed by
23 * entity storage classes; see the
24 * @link entity_api Entity API topic @endlink for more information. Most
25 * entities use or extend the default classes:
26 * \Drupal\Core\Entity\Sql\SqlContentEntityStorage for content entities, and
27 * \Drupal\Core\Config\Entity\ConfigEntityStorage for configuration entities.
28 * For these entities, there is a set of hooks that is invoked for each
29 * CRUD operation, which module developers can implement to affect these
30 * operations; these hooks are actually invoked from methods on
31 * \Drupal\Core\Entity\EntityStorageBase.
32 *
33 * For content entities, viewing and rendering are handled by a view builder
34 * class; see the @link entity_api Entity API topic @endlink for more
35 * information. Most view builders extend or use the default class
36 * \Drupal\Core\Entity\EntityViewBuilder.
37 *
38 * Entity editing (including adding new entities) is handled by entity form
39 * classes; see the @link entity_api Entity API topic @endlink for more
40 * information. Most entity editing forms extend base classes
41 * \Drupal\Core\Entity\EntityForm or \Drupal\Core\Entity\ContentEntityForm.
42 * Note that many other operations, such as confirming deletion of entities,
43 * also use entity form classes.
44 *
45 * This topic lists all of the entity CRUD and view operations, and the hooks
46 * and other operations that are invoked (in order) for each operation. Some
47 * notes:
48 * - Whenever an entity hook is invoked, there is both a type-specific entity
49 *   hook, and a generic entity hook. For instance, during a create operation on
50 *   a node, first hook_node_create() and then hook_entity_create() would be
51 *   invoked.
52 * - The entity-type-specific hooks are represented in the list below as
53 *   hook_ENTITY_TYPE_... (hook_ENTITY_TYPE_create() in this example). To
54 *   implement one of these hooks for an entity whose machine name is "foo",
55 *   define a function called mymodule_foo_create(), for instance. Also note
56 *   that the entity or array of entities that are passed into a specific-type
57 *   hook are of the specific entity class, not the generic Entity class, so in
58 *   your implementation, you can make the $entity argument something like $node
59 *   and give it a specific type hint (which should normally be to the specific
60 *   interface, such as \Drupal\node\NodeInterface for nodes).
61 * - $storage in the code examples is assumed to be an entity storage
62 *   class. See the @link entity_api Entity API topic @endlink for
63 *   information on how to instantiate the correct storage class for an
64 *   entity type.
65 * - $view_builder in the code examples is assumed to be an entity view builder
66 *   class. See the @link entity_api Entity API topic @endlink for
67 *   information on how to instantiate the correct view builder class for
68 *   an entity type.
69 * - During many operations, static methods are called on the entity class,
70 *   which implements \Drupal\Core\Entity\EntityInterface.
71 *
72 * @section entities_revisions_translations Entities, revisions and translations
73 * A content entity can have multiple stored variants: based on its definition,
74 * it can be revisionable, translatable, or both.
75 *
76 * A revisionable entity can keep track of the changes that affect its data. In
77 * fact all previous revisions of the entity can be stored and made available as
78 * "historical" information. The "default" revision is the canonical variant of
79 * the entity, the one that is loaded when no specific revision is requested.
80 * Only changes to the default revision may be performed without triggering the
81 * creation of a new revision, in any other case revision data is not supposed
82 * to change. Aside from historical revisions, there can be "pending" revisions,
83 * that contain changes that did not make their way into the default revision.
84 * Typically these revisions contain data that is waiting for some form of
85 * approval, before being accepted as canonical.
86 * @see \Drupal\Core\Entity\RevisionableInterface
87 * @see \Drupal\Core\Entity\RevisionableStorageInterface
88 *
89 * A translatable entity can contain multiple translations of the same content.
90 * Content entity data is stored via fields, and each field can have one version
91 * for each enabled language. Some fields may be defined as untranslatable,
92 * which means that their values are shared among all translations. The
93 * "default" translation is the canonical variant of the entity, the one whose
94 * content will be accessible in the entity field data. Other translations
95 * can be instantiated from the default one. Every translation has an "active
96 * language" that is used to determine which field translation values should be
97 * handled. Typically the default translation's active language is the language
98 * of the content that was originally entered and served as source for the other
99 * translations.
100 * @see \Drupal\Core\Entity\TranslatableInterface
101 * @see \Drupal\Core\Entity\TranslatableStorageInterface
102 *
103 * An entity that is both revisionable and translatable has all the features
104 * described above: every revision can contain one or more translations. The
105 * canonical variant of the entity is the default translation of the default
106 * revision. Any revision will be initially loaded as the default translation,
107 * the other revision translations can be instantiated from this one. If a
108 * translation has changes in a certain revision, the translation is considered
109 * "affected" by that revision, and will be flagged as such via the
110 * "revision_translation_affected" field. With the built-in UI, every time a new
111 * revision is saved, the changes for the edited translations will be stored,
112 * while all field values for the other translations will be copied as-is.
113 * However, if multiple translations of the default revision are being
114 * subsequently modified without creating a new revision when saving, they will
115 * all be affected by the default revision. Additionally, all revision
116 * translations will be affected when saving a revision containing changes for
117 * untranslatable fields. On the other hand, pending revisions are not supposed
118 * to contain multiple affected translations, even when they are being
119 * manipulated via the API.
120 * @see \Drupal\Core\Entity\TranslatableRevisionableInterface
121 * @see \Drupal\Core\Entity\TranslatableRevisionableStorageInterface
122 *
123 * @section create Create operations
124 * To create an entity:
125 * @code
126 * $entity = $storage->create();
127 *
128 * // Add code here to set properties on the entity.
129 *
130 * // Until you call save(), the entity is just in memory.
131 * $entity->save();
132 * @endcode
133 * There is also a shortcut method on entity classes, which creates an entity
134 * with an array of provided property values: \Drupal\Core\Entity::create().
135 *
136 * Hooks invoked during the create operation:
137 * - hook_ENTITY_TYPE_create()
138 * - hook_entity_create()
139 * - When handling content entities, if a new translation is added to the entity
140 *   object:
141 *   - hook_ENTITY_TYPE_translation_create()
142 *   - hook_entity_translation_create()
143 *
144 * See @ref save below for the save portion of the operation.
145 *
146 * @section load Read/Load operations
147 * To load (read) a single entity:
148 * @code
149 * $entity = $storage->load($id);
150 * @endcode
151 * To load multiple entities:
152 * @code
153 * $entities = $storage->loadMultiple($ids);
154 * @endcode
155 * Since load() calls loadMultiple(), these are really the same operation.
156 * Here is the order of hooks and other operations that take place during
157 * entity loading:
158 * - Entity is loaded from storage.
159 * - postLoad() is called on the entity class, passing in all of the loaded
160 *   entities.
161 * - hook_entity_load()
162 * - hook_ENTITY_TYPE_load()
163 *
164 * When an entity is loaded, normally the default entity revision is loaded.
165 * It is also possible to load a different revision, for entities that support
166 * revisions, with this code:
167 * @code
168 * $entity = $storage->loadRevision($revision_id);
169 * @endcode
170 * This involves the same hooks and operations as regular entity loading.
171 *
172 * The "latest revision" of an entity is the most recently created one,
173 * regardless of it being default or pending. If the entity is translatable,
174 * revision translations are not taken into account either. In other words, any
175 * time a new revision is created, that becomes the latest revision for the
176 * entity overall, regardless of the affected translations. To load the latest
177 * revision of an entity:
178 * @code
179 * $revision_id = $storage->getLatestRevisionId($entity_id);
180 * $entity = $storage->loadRevision($revision_id);
181 * @endcode
182 * As usual, if the entity is translatable, this code instantiates into $entity
183 * the default translation of the revision, even if the latest revision contains
184 * only changes to a different translation:
185 * @code
186 * $is_default = $entity->isDefaultTranslation(); // returns TRUE
187 * @endcode
188 *
189 * The "latest translation-affected revision" is the most recently created one
190 * that affects the specified translation. For example, when a new revision
191 * introducing some changes to an English translation is saved, that becomes the
192 * new "latest revision". However, if an existing Italian translation was not
193 * affected by those changes, then the "latest translation-affected revision"
194 * for Italian remains what it was. To load the Italian translation at its
195 * latest translation-affected revision:
196 * @code
197 * $revision_id = $storage->getLatestTranslationAffectedRevisionId($entity_id, 'it');
198 * $it_translation = $storage->loadRevision($revision_id)->getTranslation('it');
199 * @endcode
200 *
201 * @section save Save operations
202 * To update an existing entity, you will need to load it, change properties,
203 * and then save; as described above, when creating a new entity, you will also
204 * need to save it. Here is the order of hooks and other events that happen
205 * during an entity save:
206 * - preSave() is called on the entity object, and field objects.
207 * - hook_ENTITY_TYPE_presave()
208 * - hook_entity_presave()
209 * - Entity is saved to storage.
210 * - For updates on content entities, if there is a translation added that
211 *   was not previously present:
212 *   - hook_ENTITY_TYPE_translation_insert()
213 *   - hook_entity_translation_insert()
214 * - For updates on content entities, if there was a translation removed:
215 *   - hook_ENTITY_TYPE_translation_delete()
216 *   - hook_entity_translation_delete()
217 * - postSave() is called on the entity object.
218 * - hook_ENTITY_TYPE_insert() (new) or hook_ENTITY_TYPE_update() (update)
219 * - hook_entity_insert() (new) or hook_entity_update() (update)
220 *
221 * Some specific entity types invoke hooks during preSave() or postSave()
222 * operations. Examples:
223 * - Field configuration preSave(): hook_field_storage_config_update_forbid()
224 * - Node postSave(): hook_node_access_records() and
225 *   hook_node_access_records_alter()
226 * - Config entities that are acting as entity bundles in postSave():
227 *   hook_entity_bundle_create()
228 * - Comment: hook_comment_publish() and hook_comment_unpublish() as
229 *   appropriate.
230 *
231 * Note that all translations available for the entity are stored during a save
232 * operation. When saving a new revision, a copy of every translation is stored,
233 * regardless of it being affected by the revision.
234 *
235 * @section edit Editing operations
236 * When an entity's add/edit form is used to add or edit an entity, there
237 * are several hooks that are invoked:
238 * - hook_entity_prepare_form()
239 * - hook_ENTITY_TYPE_prepare_form()
240 * - hook_entity_form_display_alter() (for content entities only)
241 *
242 * @section delete Delete operations
243 * To delete one or more entities, load them and then delete them:
244 * @code
245 * $entities = $storage->loadMultiple($ids);
246 * $storage->delete($entities);
247 * @endcode
248 *
249 * During the delete operation, the following hooks and other events happen:
250 * - preDelete() is called on the entity class.
251 * - hook_ENTITY_TYPE_predelete()
252 * - hook_entity_predelete()
253 * - Entity and field information is removed from storage.
254 * - postDelete() is called on the entity class.
255 * - hook_ENTITY_TYPE_delete()
256 * - hook_entity_delete()
257 *
258 * Some specific entity types invoke hooks during the delete process. Examples:
259 * - Entity bundle postDelete(): hook_entity_bundle_delete()
260 *
261 * Individual revisions of an entity can also be deleted:
262 * @code
263 * $storage->deleteRevision($revision_id);
264 * @endcode
265 * This operation invokes the following operations and hooks:
266 * - Revision is loaded (see @ref load above).
267 * - Revision and field information is removed from the database.
268 * - hook_ENTITY_TYPE_revision_delete()
269 * - hook_entity_revision_delete()
270 *
271 * @section view View/render operations
272 * To make a render array for a loaded entity:
273 * @code
274 * // You can omit the language ID if the default language is being used.
275 * $build = $view_builder->view($entity, 'view_mode_name', $language->getId());
276 * @endcode
277 * You can also use the viewMultiple() method to view multiple entities.
278 *
279 * Hooks invoked during the operation of building a render array:
280 * - hook_entity_view_mode_alter()
281 * - hook_ENTITY_TYPE_build_defaults_alter()
282 * - hook_entity_build_defaults_alter()
283 *
284 * View builders for some types override these hooks, notably:
285 * - The Tour view builder does not invoke any hooks.
286 * - The Block view builder invokes hook_block_view_alter() and
287 *   hook_block_view_BASE_BLOCK_ID_alter(). Note that in other view builders,
288 *   the view alter hooks are run later in the process.
289 *
290 * During the rendering operation, the default entity viewer runs the following
291 * hooks and operations in the pre-render step:
292 * - hook_entity_view_display_alter()
293 * - hook_entity_prepare_view()
294 * - Entity fields are loaded, and render arrays are built for them using
295 *   their formatters.
296 * - hook_entity_display_build_alter()
297 * - hook_ENTITY_TYPE_view()
298 * - hook_entity_view()
299 * - hook_ENTITY_TYPE_view_alter()
300 * - hook_entity_view_alter()
301 *
302 * Some specific builders have specific hooks:
303 * - The Node view builder invokes hook_node_links_alter().
304 * - The Comment view builder invokes hook_comment_links_alter().
305 *
306 * After this point in rendering, the theme system takes over. See the
307 * @link theme_render Theme system and render API topic @endlink for more
308 * information.
309 *
310 * @section misc Other entity hooks
311 * Some types of entities invoke hooks for specific operations:
312 * - Searching nodes:
313 *   - hook_ranking()
314 *   - Query is executed to find matching nodes
315 *   - Resulting node is loaded
316 *   - Node render array is built
317 *   - comment_node_update_index() is called (this adds "N comments" text)
318 *   - hook_node_search_result()
319 * - Search indexing nodes:
320 *   - Node is loaded
321 *   - Node render array is built
322 *   - hook_node_update_index()
323 * @}
324 */
325
326/**
327 * @defgroup entity_api Entity API
328 * @{
329 * Describes how to define and manipulate content and configuration entities.
330 *
331 * Entities, in Drupal, are objects that are used for persistent storage of
332 * content and configuration information. See the
333 * @link info_types Information types topic @endlink for an overview of the
334 * different types of information, and the
335 * @link config_api Configuration API topic @endlink for more about the
336 * configuration API.
337 *
338 * Each entity is an instance of a particular "entity type". Some content entity
339 * types have sub-types, which are known as "bundles", while for other entity
340 * types, there is only a single bundle. For example, the Node content entity
341 * type, which is used for the main content pages in Drupal, has bundles that
342 * are known as "content types", while the User content type, which is used for
343 * user accounts, has only one bundle.
344 *
345 * The sections below have more information about entities and the Entity API;
346 * for more detailed information, see
347 * https://www.drupal.org/developing/api/entity.
348 *
349 * @section define Defining an entity type
350 * Entity types are defined by modules, using Drupal's Plugin API (see the
351 * @link plugin_api Plugin API topic @endlink for more information about plugins
352 * in general). Here are the steps to follow to define a new entity type:
353 * - Choose a unique machine name, or ID, for your entity type. This normally
354 *   starts with (or is the same as) your module's machine name. It should be
355 *   as short as possible, and may not exceed 32 characters.
356 * - Define an interface for your entity's get/set methods, usually extending
357 *   either \Drupal\Core\Config\Entity\ConfigEntityInterface or
358 *   \Drupal\Core\Entity\ContentEntityInterface.
359 * - Define a class for your entity, implementing your interface and extending
360 *   either \Drupal\Core\Config\Entity\ConfigEntityBase or
361 *   \Drupal\Core\Entity\ContentEntityBase, with annotation for
362 *   \@ConfigEntityType or \@ContentEntityType in its documentation block.
363 *   If you are defining a content entity type, it is recommended to extend the
364 *   \Drupal\Core\Entity\EditorialContentEntityBase base class in order to get
365 *   out-of-the-box support for Entity API's revisioning and publishing
366 *   features, which will allow your entity type to be used with Drupal's
367 *   editorial workflow provided by the Content Moderation module.
368 * - In the annotation, the 'id' property gives the entity type ID, and the
369 *   'label' property gives the human-readable name of the entity type. If you
370 *   are defining a content entity type that uses bundles, the 'bundle_label'
371 *   property gives the human-readable name to use for a bundle of this entity
372 *   type (for example, "Content type" for the Node entity).
373 * - The annotation will refer to several handler classes, which you will also
374 *   need to define:
375 *   - list_builder: Define a class that extends
376 *     \Drupal\Core\Config\Entity\ConfigEntityListBuilder (for configuration
377 *     entities) or \Drupal\Core\Entity\EntityListBuilder (for content
378 *     entities), to provide an administrative overview for your entities.
379 *   - add and edit forms, or default form: Define a class (or two) that
380 *     extend(s) \Drupal\Core\Entity\EntityForm to provide add and edit forms
381 *     for your entities. For content entities, base class
382 *     \Drupal\Core\Entity\ContentEntityForm is a better starting point.
383 *   - delete form: Define a class that extends
384 *     \Drupal\Core\Entity\EntityConfirmFormBase to provide a delete
385 *     confirmation form for your entities.
386 *   - view_builder: For content entities and config entities that need to be
387 *     viewed, define a class that implements
388 *     \Drupal\Core\Entity\EntityViewBuilderInterface (usually extending
389 *     \Drupal\Core\Entity\EntityViewBuilder), to display a single entity.
390 *   - translation: For translatable content entities (if the 'translatable'
391 *     annotation property has value TRUE), define a class that extends
392 *     \Drupal\content_translation\ContentTranslationHandler, to translate
393 *     the content. Configuration translation is handled automatically by the
394 *     Configuration Translation module, without the need of a handler class.
395 *   - access: If your configuration entity has complex permissions, you might
396 *     need an access control handling, implementing
397 *     \Drupal\Core\Entity\EntityAccessControlHandlerInterface, but most
398 *     entities can just use the 'admin_permission' annotation property
399 *     instead. Note that if you are creating your own access control handler,
400 *     you should override the checkAccess() and checkCreateAccess() methods,
401 *     not access().
402 *   - storage: A class implementing
403 *     \Drupal\Core\Entity\EntityStorageInterface. If not specified, content
404 *     entities will use \Drupal\Core\Entity\Sql\SqlContentEntityStorage, and
405 *     config entities will use \Drupal\Core\Config\Entity\ConfigEntityStorage.
406 *     You can extend one of these classes to provide custom behavior.
407 *   - views_data: A class implementing \Drupal\views\EntityViewsDataInterface
408 *     to provide views data for the entity type. You can autogenerate most of
409 *     the views data by extending \Drupal\views\EntityViewsData.
410 * - For content entities, the annotation will refer to a number of database
411 *   tables and their fields. These annotation properties, such as 'base_table',
412 *   'data_table', 'entity_keys', etc., are documented on
413 *   \Drupal\Core\Entity\EntityType.
414 * - For content entities that are displayed on their own pages, the annotation
415 *   will refer to a 'uri_callback' function, which takes an object of the
416 *   entity interface you have defined as its parameter, and returns routing
417 *   information for the entity page; see node_uri() for an example. You will
418 *   also need to add a corresponding route to your module's routing.yml file;
419 *   see the entity.node.canonical route in node.routing.yml for an example, and see
420 *   @ref sec_routes below for some notes.
421 * - Optionally, instead of defining routes, routes can be auto generated by
422 *   providing a route handler. See @ref sec_routes. Otherwise, define routes
423 *   and links for the various URLs associated with the entity.
424 *   These go into the 'links' annotation, with the link type as the key, and
425 *   the path of this link template as the value. The corresponding route
426 *   requires the following route name:
427 *   "entity.$entity_type_id.$link_template_type". See @ref sec_routes below for
428 *   some routing notes. Typical link types are:
429 *   - canonical: Default link, either to view (if entities are viewed on their
430 *     own pages) or edit the entity.
431 *   - delete-form: Confirmation form to delete the entity.
432 *   - edit-form: Editing form.
433 *   - Other link types specific to your entity type can also be defined.
434 * - If your content entity is fieldable, provide the 'field_ui_base_route'
435 *   annotation property, giving the name of the route that the Manage Fields,
436 *   Manage Display, and Manage Form Display pages from the Field UI module
437 *   will be attached to. This is usually the bundle settings edit page, or an
438 *   entity type settings page if there are no bundles.
439 * - If your content entity has bundles, you will also need to define a second
440 *   plugin to handle the bundles. This plugin is itself a configuration entity
441 *   type, so follow the steps here to define it. The machine name ('id'
442 *   annotation property) of this configuration entity class goes into the
443 *   'bundle_entity_type' annotation property on the entity type class. For
444 *   example, for the Node entity, the bundle class is
445 *   \Drupal\node\Entity\NodeType, whose machine name is 'node_type'. This is
446 *   the annotation property 'bundle_entity_type' on the
447 *   \Drupal\node\Entity\Node class. Also, the
448 *   bundle config entity type annotation must have a 'bundle_of' property,
449 *   giving the machine name of the entity type it is acting as a bundle for.
450 *   These machine names are considered permanent, they may not be renamed.
451 * - Additional annotation properties can be seen on entity class examples such
452 *   as \Drupal\node\Entity\Node (content) and \Drupal\user\Entity\Role
453 *   (configuration). These annotation properties are documented on
454 *   \Drupal\Core\Entity\EntityType.
455 *
456 * @section sec_routes Entity routes
457 * Entity routes can be defined in *.routing.yml files, like any other route:
458 * see the @link routing Routing API @endlink topic for more information.
459 * Another option for entity routes is to use a route provider class, and
460 * reference it in the annotations on the entity class: see the end of this
461 * section for an example.
462 *
463 * It's possible to use both a YAML file and a provider class for entity
464 * routes, at the same time. Avoid duplicating route names between the two:
465 * if a duplicate route name is found in both locations, the one in the YAML
466 * file takes precedence; regardless, such duplication can be confusing.
467 *
468 * Here's an example YAML route specification, for the block configure form:
469 * @code
470 * entity.block.edit_form:
471 *   path: '/admin/structure/block/manage/{block}'
472 *   defaults:
473 *     _entity_form: 'block.default'
474 *     _title: 'Configure block'
475 *   requirements:
476 *     _entity_access: 'block.update'
477 * @endcode
478 * Some notes on this example:
479 * - path: The {block} in the path is a placeholder, which (for an entity) must
480 *   always take the form of {machine_name_of_entity_type}. In the URL, the
481 *   placeholder value will be the ID of an entity item. When the route is used,
482 *   the entity system will load the corresponding entity item and pass it in as
483 *   an object to the controller for the route.
484 * - defaults: For entity form routes, use _entity_form rather than the generic
485 *   _controller or _form. The value is composed of the entity type machine name
486 *   and a form handler type from the entity annotation (see @ref define above
487 *   for more on handlers and annotation). So, in this example, block.default
488 *   refers to the 'default' form handler on the block entity type, whose
489 *   annotation contains:
490 *   @code
491 *   handlers = {
492 *     "form" = {
493 *       "default" = "Drupal\block\BlockForm",
494 *   @endcode
495 * If instead of YAML you want to use a route provider class:
496 * - \Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider provides canonical,
497 *   edit-form, and delete-form routes.
498 * - \Drupal\Core\Entity\Routing\AdminHtmlRouteProvider provides the same
499 *   routes, set up to use the administrative theme for edit and delete pages.
500 * - You can also create your own class, extending one of these two classes if
501 *   you only want to modify their behavior slightly.
502 *
503 * To register any route provider class, add lines like the following to your
504 * entity class annotation:
505 * @code
506 * handlers = {
507 *   "route_provider" = {
508 *     "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
509 * @endcode
510 *
511 * @section bundle Defining a content entity bundle
512 * For entity types that use bundles, such as Node (bundles are content types)
513 * and Taxonomy (bundles are vocabularies), modules and install profiles can
514 * define bundles by supplying default configuration in their config/install
515 * directories. (See the @link config_api Configuration API topic @endlink for
516 * general information about configuration.)
517 *
518 * There are several good examples of this in Drupal Core:
519 * - The Forum module defines a content type in node.type.forum.yml and a
520 *   vocabulary in taxonomy.vocabulary.forums.yml
521 * - The Book module defines a content type in node.type.book.yml
522 * - The Standard install profile defines Page and Article content types in
523 *   node.type.page.yml and node.type.article.yml, a Tags vocabulary in
524 *   taxonomy.vocabulary.tags.yml, and a Node comment type in
525 *   comment.type.comment.yml. This profile's configuration is especially
526 *   instructive, because it also adds several fields to the Article type, and
527 *   it sets up view and form display modes for the node types.
528 *
529 * @section load_query Loading, querying, and rendering entities
530 * To load entities, use the entity storage manager, which is an object
531 * implementing \Drupal\Core\Entity\EntityStorageInterface that you can
532 * retrieve with:
533 * @code
534 * $storage = \Drupal::entityTypeManager()->getStorage('your_entity_type');
535 * // Or if you have a $container variable:
536 * $storage = $container->get('entity_type.manager')->getStorage('your_entity_type');
537 * @endcode
538 * Here, 'your_entity_type' is the machine name of your entity type ('id'
539 * annotation property on the entity class), and note that you should use
540 * dependency injection to retrieve this object if possible. See the
541 * @link container Services and Dependency Injection topic @endlink for more
542 * about how to properly retrieve services.
543 *
544 * To query to find entities to load, use an entity query, which is an object
545 * implementing \Drupal\Core\Entity\Query\QueryInterface that you can retrieve
546 * with:
547 * @code
548 * // Simple query:
549 * $query = \Drupal::entityQuery('your_entity_type');
550 * // Or, if you have a $container variable:
551 * $storage = $container->get('entity_type.manager')->getStorage('your_entity_type');
552 * $query = $storage->getQuery();
553 * @endcode
554 * If you need aggregation, there is an aggregate query available, which
555 * implements \Drupal\Core\Entity\Query\QueryAggregateInterface:
556 * @code
557 * $query \Drupal::entityQueryAggregate('your_entity_type');
558 * // Or:
559 * $query = $storage->getAggregateQuery('your_entity_type');
560 * @endcode
561 *
562 * In either case, you can then add conditions to your query, using methods
563 * like condition(), exists(), etc. on $query; add sorting, pager, and range
564 * if needed, and execute the query to return a list of entity IDs that match
565 * the query.
566 *
567 * Here is an example, using the core File entity:
568 * @code
569 * $fids = Drupal::entityQuery('file')
570 *   ->condition('status', FILE_STATUS_PERMANENT, '<>')
571 *   ->condition('changed', REQUEST_TIME - $age, '<')
572 *   ->range(0, 100)
573 *   ->execute();
574 * $files = $storage->loadMultiple($fids);
575 * @endcode
576 *
577 * The normal way of viewing entities is by using a route, as described in the
578 * sections above. If for some reason you need to render an entity in code in a
579 * particular view mode, you can use an entity view builder, which is an object
580 * implementing \Drupal\Core\Entity\EntityViewBuilderInterface that you can
581 * retrieve with:
582 * @code
583 * $view_builder = \Drupal::entityTypeManager()->getViewBuilder('your_entity_type');
584 * // Or if you have a $container variable:
585 * $view_builder = $container->get('entity_type.manager')->getViewBuilder('your_entity_type');
586 * @endcode
587 * Then, to build and render the entity:
588 * @code
589 * // You can omit the language ID, by default the current content language will
590 * // be used. If no translation is available for the current language, fallback
591 * // rules will be used.
592 * $build = $view_builder->view($entity, 'view_mode_name', $language->getId());
593 * // $build is a render array.
594 * $rendered = \Drupal::service('renderer')->render($build);
595 * @endcode
596 *
597 * @section sec_access Access checking on entities
598 * Entity types define their access permission scheme in their annotation.
599 * Access permissions can be quite complex, so you should not assume any
600 * particular permission scheme. Instead, once you have an entity object
601 * loaded, you can check for permission for a particular operation (such as
602 * 'view') at the entity or field level by calling:
603 * @code
604 * $entity->access($operation);
605 * $entity->nameOfField->access($operation);
606 * @endcode
607 * The interface related to access checking in entities and fields is
608 * \Drupal\Core\Access\AccessibleInterface.
609 *
610 * The default entity access control handler invokes two hooks while checking
611 * access on a single entity: hook_entity_access() is invoked first, and
612 * then hook_ENTITY_TYPE_access() (where ENTITY_TYPE is the machine name
613 * of the entity type). If no module returns a TRUE or FALSE value from
614 * either of these hooks, then the entity's default access checking takes
615 * place. For create operations (creating a new entity), the hooks that
616 * are invoked are hook_entity_create_access() and
617 * hook_ENTITY_TYPE_create_access() instead.
618 *
619 * The access to an entity can be influenced in several ways:
620 * - To explicitly allow access, return an AccessResultInterface object with
621 * isAllowed() returning TRUE. Other modules can override this access by
622 * returning TRUE for isForbidden().
623 * - To explicitly forbid access, return an AccessResultInterface object with
624 * isForbidden() returning TRUE. Access will be forbidden even if your module
625 * (or another module) also returns TRUE for isNeutral() or isAllowed().
626 * - To neither allow nor explicitly forbid access, return an
627 * AccessResultInterface object with isNeutral() returning TRUE.
628 * - If your module does not return an AccessResultInterface object, neutral
629 * access will be assumed.
630 *
631 * The Node entity type has a complex system for determining access, which
632 * developers can interact with. This is described in the
633 * @link node_access Node access topic. @endlink
634 *
635 * @see i18n
636 * @see entity_crud
637 * @see \Drupal\Core\Entity\EntityRepositoryInterface::getTranslationFromContext()
638 * @}
639 */
640
641/**
642 * @addtogroup hooks
643 * @{
644 */
645
646/**
647 * Control entity operation access.
648 *
649 * Note that this hook is not called for listings (e.g., from entity queries
650 * and Views). For nodes, see @link node_access Node access rights @endlink for
651 * a full explanation. For other entity types, see hook_query_TAG_alter().
652 *
653 * @param \Drupal\Core\Entity\EntityInterface $entity
654 *   The entity to check access to.
655 * @param string $operation
656 *   The operation that is to be performed on $entity. Usually one of:
657 *   - "view"
658 *   - "update"
659 *   - "delete"
660 * @param \Drupal\Core\Session\AccountInterface $account
661 *   The account trying to access the entity.
662 *
663 * @return \Drupal\Core\Access\AccessResultInterface
664 *   The access result. The final result is calculated by using
665 *   \Drupal\Core\Access\AccessResultInterface::orIf() on the result of every
666 *   hook_entity_access() and hook_ENTITY_TYPE_access() implementation, and the
667 *   result of the entity-specific checkAccess() method in the entity access
668 *   control handler. Be careful when writing generalized access checks shared
669 *   between routing and entity checks: routing uses the andIf() operator. So
670 *   returning an isNeutral() does not determine entity access at all but it
671 *   always ends up denying access while routing.
672 *
673 * @see \Drupal\Core\Entity\EntityAccessControlHandler
674 * @see hook_entity_create_access()
675 * @see hook_ENTITY_TYPE_access()
676 * @see hook_query_TAG_alter()
677 *
678 * @ingroup entity_api
679 */
680function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account) {
681  // No opinion.
682  return AccessResult::neutral();
683}
684
685/**
686 * Control entity operation access for a specific entity type.
687 *
688 * Note that this hook is not called for listings (e.g., from entity queries
689 * and Views). For nodes, see @link node_access Node access rights @endlink for
690 * a full explanation. For other entity types, see hook_query_TAG_alter().
691 *
692 * @param \Drupal\Core\Entity\EntityInterface $entity
693 *   The entity to check access to.
694 * @param string $operation
695 *   The operation that is to be performed on $entity. Usually one of:
696 *   - "view"
697 *   - "update"
698 *   - "delete"
699 * @param \Drupal\Core\Session\AccountInterface $account
700 *   The account trying to access the entity.
701 *
702 * @return \Drupal\Core\Access\AccessResultInterface
703 *   The access result. hook_entity_access() has detailed documentation.
704 *
705 * @see \Drupal\Core\Entity\EntityAccessControlHandler
706 * @see hook_ENTITY_TYPE_create_access()
707 * @see hook_entity_access()
708 * @see hook_query_TAG_alter()
709 *
710 * @ingroup entity_api
711 */
712function hook_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account) {
713  // No opinion.
714  return AccessResult::neutral();
715}
716
717/**
718 * Control entity create access.
719 *
720 * @param \Drupal\Core\Session\AccountInterface $account
721 *   The account trying to access the entity.
722 * @param array $context
723 *   An associative array of additional context values. By default it contains
724 *   language and the entity type ID:
725 *   - entity_type_id - the entity type ID.
726 *   - langcode - the current language code.
727 * @param string $entity_bundle
728 *   The entity bundle name.
729 *
730 * @return \Drupal\Core\Access\AccessResultInterface
731 *   The access result.
732 *
733 * @see \Drupal\Core\Entity\EntityAccessControlHandler
734 * @see hook_entity_access()
735 * @see hook_ENTITY_TYPE_create_access()
736 *
737 * @ingroup entity_api
738 */
739function hook_entity_create_access(\Drupal\Core\Session\AccountInterface $account, array $context, $entity_bundle) {
740  // No opinion.
741  return AccessResult::neutral();
742}
743
744/**
745 * Control entity create access for a specific entity type.
746 *
747 * @param \Drupal\Core\Session\AccountInterface $account
748 *   The account trying to access the entity.
749 * @param array $context
750 *   An associative array of additional context values. By default it contains
751 *   language:
752 *   - langcode - the current language code.
753 * @param string $entity_bundle
754 *   The entity bundle name.
755 *
756 * @return \Drupal\Core\Access\AccessResultInterface
757 *   The access result.
758 *
759 * @see \Drupal\Core\Entity\EntityAccessControlHandler
760 * @see hook_ENTITY_TYPE_access()
761 * @see hook_entity_create_access()
762 *
763 * @ingroup entity_api
764 */
765function hook_ENTITY_TYPE_create_access(\Drupal\Core\Session\AccountInterface $account, array $context, $entity_bundle) {
766  // No opinion.
767  return AccessResult::neutral();
768}
769
770/**
771 * Add to entity type definitions.
772 *
773 * Modules may implement this hook to add information to defined entity types,
774 * as defined in \Drupal\Core\Entity\EntityTypeInterface.
775 *
776 * To alter existing information or to add information dynamically, use
777 * hook_entity_type_alter().
778 *
779 * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types
780 *   An associative array of all entity type definitions, keyed by the entity
781 *   type name. Passed by reference.
782 *
783 * @see \Drupal\Core\Entity\Entity
784 * @see \Drupal\Core\Entity\EntityTypeInterface
785 * @see hook_entity_type_alter()
786 */
787function hook_entity_type_build(array &$entity_types) {
788  /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
789  // Add a form for a custom node form without overriding the default
790  // node form. To override the default node form, use hook_entity_type_alter().
791  $entity_types['node']->setFormClass('mymodule_foo', 'Drupal\mymodule\NodeFooForm');
792}
793
794/**
795 * Alter the entity type definitions.
796 *
797 * Modules may implement this hook to alter the information that defines an
798 * entity type. All properties that are available in
799 * \Drupal\Core\Entity\Annotation\EntityType and all the ones additionally
800 * provided by modules can be altered here.
801 *
802 * Do not use this hook to add information to entity types, unless one of the
803 * following is true:
804 * - You are filling in default values.
805 * - You need to dynamically add information only in certain circumstances.
806 * - Your hook needs to run after hook_entity_type_build() implementations.
807 * Use hook_entity_type_build() instead in all other cases.
808 *
809 * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types
810 *   An associative array of all entity type definitions, keyed by the entity
811 *   type name. Passed by reference.
812 *
813 * @see \Drupal\Core\Entity\Entity
814 * @see \Drupal\Core\Entity\EntityTypeInterface
815 */
816function hook_entity_type_alter(array &$entity_types) {
817  /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
818  // Set the controller class for nodes to an alternate implementation of the
819  // Drupal\Core\Entity\EntityStorageInterface interface.
820  $entity_types['node']->setStorageClass('Drupal\mymodule\MyCustomNodeStorage');
821}
822
823/**
824 * Alter the view modes for entity types.
825 *
826 * @param array $view_modes
827 *   An array of view modes, keyed first by entity type, then by view mode name.
828 *
829 * @see \Drupal\Core\Entity\EntityDisplayRepositoryInterface::getAllViewModes()
830 * @see \Drupal\Core\Entity\EntityDisplayRepositoryInterface::getViewModes()
831 */
832function hook_entity_view_mode_info_alter(&$view_modes) {
833  $view_modes['user']['full']['status'] = TRUE;
834}
835
836/**
837 * Describe the bundles for entity types.
838 *
839 * @return array
840 *   An associative array of all entity bundles, keyed by the entity
841 *   type name, and then the bundle name, with the following keys:
842 *   - label: The human-readable name of the bundle.
843 *   - uri_callback: (optional) The same as the 'uri_callback' key defined for
844 *     the entity type in the EntityTypeManager, but for the bundle only. When
845 *     determining the URI of an entity, if a 'uri_callback' is defined for both
846 *     the entity type and the bundle, the one for the bundle is used.
847 *   - translatable: (optional) A boolean value specifying whether this bundle
848 *     has translation support enabled. Defaults to FALSE.
849 *
850 * @see \Drupal\Core\Entity\EntityTypeBundleInfo::getBundleInfo()
851 * @see hook_entity_bundle_info_alter()
852 */
853function hook_entity_bundle_info() {
854  $bundles['user']['user']['label'] = t('User');
855  return $bundles;
856}
857
858/**
859 * Alter the bundles for entity types.
860 *
861 * @param array $bundles
862 *   An array of bundles, keyed first by entity type, then by bundle name.
863 *
864 * @see Drupal\Core\Entity\EntityTypeBundleInfo::getBundleInfo()
865 * @see hook_entity_bundle_info()
866 */
867function hook_entity_bundle_info_alter(&$bundles) {
868  $bundles['user']['user']['label'] = t('Full account');
869}
870
871/**
872 * Act on entity_bundle_create().
873 *
874 * This hook is invoked after the operation has been performed.
875 *
876 * @param string $entity_type_id
877 *   The type of $entity; e.g. 'node' or 'user'.
878 * @param string $bundle
879 *   The name of the bundle.
880 *
881 * @see entity_crud
882 */
883function hook_entity_bundle_create($entity_type_id, $bundle) {
884  // When a new bundle is created, the menu needs to be rebuilt to add the
885  // Field UI menu item tabs.
886  \Drupal::service('router.builder')->setRebuildNeeded();
887}
888
889/**
890 * Act on entity_bundle_delete().
891 *
892 * This hook is invoked after the operation has been performed.
893 *
894 * @param string $entity_type_id
895 *   The type of entity; for example, 'node' or 'user'.
896 * @param string $bundle
897 *   The bundle that was just deleted.
898 *
899 * @ingroup entity_crud
900 */
901function hook_entity_bundle_delete($entity_type_id, $bundle) {
902  // Remove the settings associated with the bundle in my_module.settings.
903  $config = \Drupal::config('my_module.settings');
904  $bundle_settings = $config->get('bundle_settings');
905  if (isset($bundle_settings[$entity_type_id][$bundle])) {
906    unset($bundle_settings[$entity_type_id][$bundle]);
907    $config->set('bundle_settings', $bundle_settings);
908  }
909}
910
911/**
912 * Acts when creating a new entity.
913 *
914 * This hook runs after a new entity object has just been instantiated.
915 *
916 * @param \Drupal\Core\Entity\EntityInterface $entity
917 *   The entity object.
918 *
919 * @ingroup entity_crud
920 * @see hook_ENTITY_TYPE_create()
921 */
922function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) {
923  \Drupal::logger('example')->info('Entity created: @label', ['@label' => $entity->label()]);
924}
925
926/**
927 * Acts when creating a new entity of a specific type.
928 *
929 * This hook runs after a new entity object has just been instantiated.
930 *
931 * @param \Drupal\Core\Entity\EntityInterface $entity
932 *   The entity object.
933 *
934 * @ingroup entity_crud
935 * @see hook_entity_create()
936 */
937function hook_ENTITY_TYPE_create(\Drupal\Core\Entity\EntityInterface $entity) {
938  \Drupal::logger('example')->info('ENTITY_TYPE created: @label', ['@label' => $entity->label()]);
939}
940
941/**
942 * Respond to entity revision creation.
943 *
944 * @param \Drupal\Core\Entity\EntityInterface $new_revision
945 *   The new revision that was created.
946 * @param \Drupal\Core\Entity\EntityInterface $entity
947 *   The original entity that was used to create the revision from.
948 * @param bool|null $keep_untranslatable_fields
949 *   Whether untranslatable field values were kept (TRUE) or copied from the
950 *   default revision (FALSE) when generating a merged revision. If no value was
951 *   explicitly specified (NULL), a default value of TRUE should be assumed if
952 *   the provided entity is the default translation and untranslatable fields
953 *   should only affect the default translation, FALSE otherwise.
954 *
955 * @ingroup entity_crud
956 * @see \Drupal\Core\Entity\RevisionableStorageInterface::createRevision()
957 * @see \Drupal\Core\Entity\TranslatableRevisionableStorageInterface::createRevision()
958 */
959function hook_entity_revision_create(\Drupal\Core\Entity\EntityInterface $new_revision, \Drupal\Core\Entity\EntityInterface $entity, $keep_untranslatable_fields) {
960  // Retain the value from an untranslatable field, which are by default
961  // synchronized from the default revision.
962  $new_revision->set('untranslatable_field', $entity->get('untranslatable_field'));
963}
964
965/**
966 * Respond to entity revision creation.
967 *
968 * @param \Drupal\Core\Entity\EntityInterface $new_revision
969 *   The new revision that was created.
970 * @param \Drupal\Core\Entity\EntityInterface $entity
971 *   The original entity that was used to create the revision from.
972 * @param bool|null $keep_untranslatable_fields
973 *   Whether untranslatable field values were kept (TRUE) or copied from the
974 *   default revision (FALSE) when generating a merged revision. If no value was
975 *   explicitly specified (NULL), a default value of TRUE should be assumed if
976 *   the provided entity is the default translation and untranslatable fields
977 *   should only affect the default translation, FALSE otherwise.
978 *
979 * @ingroup entity_crud
980 * @see \Drupal\Core\Entity\RevisionableStorageInterface::createRevision()
981 * @see \Drupal\Core\Entity\TranslatableRevisionableStorageInterface::createRevision()
982 */
983function hook_ENTITY_TYPE_revision_create(\Drupal\Core\Entity\EntityInterface $new_revision, \Drupal\Core\Entity\EntityInterface $entity, $keep_untranslatable_fields) {
984  // Retain the value from an untranslatable field, which are by default
985  // synchronized from the default revision.
986  $new_revision->set('untranslatable_field', $entity->get('untranslatable_field'));
987}
988
989/**
990 * Act on an array of entity IDs before they are loaded.
991 *
992 * This hook can be used by modules that need, for example, to return a
993 * different revision than the default one.
994 *
995 * @param array $ids
996 *   An array of entity IDs that have to be loaded.
997 * @param string $entity_type_id
998 *   The type of entities being loaded (i.e. node, user, comment).
999 *
1000 * @return \Drupal\Core\Entity\EntityInterface[]
1001 *   An array of pre-loaded entity objects.
1002 *
1003 * @ingroup entity_crud
1004 */
1005function hook_entity_preload(array $ids, $entity_type_id) {
1006  $entities = [];
1007
1008  foreach ($ids as $id) {
1009    $entities[] = mymodule_swap_revision($id);
1010  }
1011
1012  return $entities;
1013}
1014
1015/**
1016 * Act on entities when loaded.
1017 *
1018 * This is a generic load hook called for all entity types loaded via the
1019 * entity API.
1020 *
1021 * hook_entity_storage_load() should be used to load additional data for
1022 * content entities.
1023 *
1024 * @param \Drupal\Core\Entity\EntityInterface[] $entities
1025 *   The entities keyed by entity ID.
1026 * @param string $entity_type_id
1027 *   The type of entities being loaded (i.e. node, user, comment).
1028 *
1029 * @ingroup entity_crud
1030 * @see hook_ENTITY_TYPE_load()
1031 */
1032function hook_entity_load(array $entities, $entity_type_id) {
1033  foreach ($entities as $entity) {
1034    $entity->foo = mymodule_add_something($entity);
1035  }
1036}
1037
1038/**
1039 * Act on entities of a specific type when loaded.
1040 *
1041 * @param array $entities
1042 *   The entities keyed by entity ID.
1043 *
1044 * @ingroup entity_crud
1045 * @see hook_entity_load()
1046 */
1047function hook_ENTITY_TYPE_load($entities) {
1048  foreach ($entities as $entity) {
1049    $entity->foo = mymodule_add_something($entity);
1050  }
1051}
1052
1053/**
1054 * Act on content entities when loaded from the storage.
1055 *
1056 * The results of this hook will be cached.
1057 *
1058 * @param \Drupal\Core\Entity\EntityInterface[] $entities
1059 *   The entities keyed by entity ID.
1060 * @param string $entity_type
1061 *   The type of entities being loaded (i.e. node, user, comment).
1062 *
1063 * @see hook_entity_load()
1064 */
1065function hook_entity_storage_load(array $entities, $entity_type) {
1066  foreach ($entities as $entity) {
1067    $entity->foo = mymodule_add_something_uncached($entity);
1068  }
1069}
1070
1071/**
1072 * Act on content entities of a given type when loaded from the storage.
1073 *
1074 * The results of this hook will be cached if the entity type supports it.
1075 *
1076 * @param \Drupal\Core\Entity\EntityInterface[] $entities
1077 *   The entities keyed by entity ID.
1078 *
1079 * @see hook_entity_storage_load()
1080 */
1081function hook_ENTITY_TYPE_storage_load(array $entities) {
1082  foreach ($entities as $entity) {
1083    $entity->foo = mymodule_add_something_uncached($entity);
1084  }
1085}
1086
1087/**
1088 * Act on an entity before it is created or updated.
1089 *
1090 * You can get the original entity object from $entity->original when it is an
1091 * update of the entity.
1092 *
1093 * @param \Drupal\Core\Entity\EntityInterface $entity
1094 *   The entity object.
1095 *
1096 * @ingroup entity_crud
1097 * @see hook_ENTITY_TYPE_presave()
1098 */
1099function hook_entity_presave(\Drupal\Core\Entity\EntityInterface $entity) {
1100  if ($entity instanceof ContentEntityInterface && $entity->isTranslatable()) {
1101    $route_match = \Drupal::routeMatch();
1102    \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->getId(), $route_match->getParameter('source_langcode'));
1103  }
1104}
1105
1106/**
1107 * Act on a specific type of entity before it is created or updated.
1108 *
1109 * You can get the original entity object from $entity->original when it is an
1110 * update of the entity.
1111 *
1112 * @param \Drupal\Core\Entity\EntityInterface $entity
1113 *   The entity object.
1114 *
1115 * @ingroup entity_crud
1116 * @see hook_entity_presave()
1117 */
1118function hook_ENTITY_TYPE_presave(\Drupal\Core\Entity\EntityInterface $entity) {
1119  if ($entity->isTranslatable()) {
1120    $route_match = \Drupal::routeMatch();
1121    \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->getId(), $route_match->getParameter('source_langcode'));
1122  }
1123}
1124
1125/**
1126 * Respond to creation of a new entity.
1127 *
1128 * This hook runs once the entity has been stored. Note that hook
1129 * implementations may not alter the stored entity data.
1130 *
1131 * @param \Drupal\Core\Entity\EntityInterface $entity
1132 *   The entity object.
1133 *
1134 * @ingroup entity_crud
1135 * @see hook_ENTITY_TYPE_insert()
1136 */
1137function hook_entity_insert(\Drupal\Core\Entity\EntityInterface $entity) {
1138  // Insert the new entity into a fictional table of all entities.
1139  \Drupal::database()->insert('example_entity')
1140    ->fields([
1141      'type' => $entity->getEntityTypeId(),
1142      'id' => $entity->id(),
1143      'created' => REQUEST_TIME,
1144      'updated' => REQUEST_TIME,
1145    ])
1146    ->execute();
1147}
1148
1149/**
1150 * Respond to creation of a new entity of a particular type.
1151 *
1152 * This hook runs once the entity has been stored. Note that hook
1153 * implementations may not alter the stored entity data.
1154 *
1155 * @param \Drupal\Core\Entity\EntityInterface $entity
1156 *   The entity object.
1157 *
1158 * @ingroup entity_crud
1159 * @see hook_entity_insert()
1160 */
1161function hook_ENTITY_TYPE_insert(\Drupal\Core\Entity\EntityInterface $entity) {
1162  // Insert the new entity into a fictional table of this type of entity.
1163  \Drupal::database()->insert('example_entity')
1164    ->fields([
1165      'id' => $entity->id(),
1166      'created' => REQUEST_TIME,
1167      'updated' => REQUEST_TIME,
1168    ])
1169    ->execute();
1170}
1171
1172/**
1173 * Respond to updates to an entity.
1174 *
1175 * This hook runs once the entity storage has been updated. Note that hook
1176 * implementations may not alter the stored entity data. Get the original entity
1177 * object from $entity->original.
1178 *
1179 * @param \Drupal\Core\Entity\EntityInterface $entity
1180 *   The entity object.
1181 *
1182 * @ingroup entity_crud
1183 * @see hook_ENTITY_TYPE_update()
1184 */
1185function hook_entity_update(\Drupal\Core\Entity\EntityInterface $entity) {
1186  // Update the entity's entry in a fictional table of all entities.
1187  \Drupal::database()->update('example_entity')
1188    ->fields([
1189      'updated' => REQUEST_TIME,
1190    ])
1191    ->condition('type', $entity->getEntityTypeId())
1192    ->condition('id', $entity->id())
1193    ->execute();
1194}
1195
1196/**
1197 * Respond to updates to an entity of a particular type.
1198 *
1199 * This hook runs once the entity storage has been updated. Note that hook
1200 * implementations may not alter the stored entity data. Get the original entity
1201 * object from $entity->original.
1202 *
1203 * @param \Drupal\Core\Entity\EntityInterface $entity
1204 *   The entity object.
1205 *
1206 * @ingroup entity_crud
1207 * @see hook_entity_update()
1208 */
1209function hook_ENTITY_TYPE_update(\Drupal\Core\Entity\EntityInterface $entity) {
1210  // Update the entity's entry in a fictional table of this type of entity.
1211  \Drupal::database()->update('example_entity')
1212    ->fields([
1213      'updated' => REQUEST_TIME,
1214    ])
1215    ->condition('id', $entity->id())
1216    ->execute();
1217}
1218
1219/**
1220 * Acts when creating a new entity translation.
1221 *
1222 * This hook runs after a new entity translation object has just been
1223 * instantiated.
1224 *
1225 * @param \Drupal\Core\Entity\EntityInterface $translation
1226 *   The entity object.
1227 *
1228 * @ingroup entity_crud
1229 * @see hook_ENTITY_TYPE_translation_create()
1230 */
1231function hook_entity_translation_create(\Drupal\Core\Entity\EntityInterface $translation) {
1232  \Drupal::logger('example')->info('Entity translation created: @label', ['@label' => $translation->label()]);
1233}
1234
1235/**
1236 * Acts when creating a new entity translation of a specific type.
1237 *
1238 * This hook runs after a new entity translation object has just been
1239 * instantiated.
1240 *
1241 * @param \Drupal\Core\Entity\EntityInterface $translation
1242 *   The entity object.
1243 *
1244 * @ingroup entity_crud
1245 * @see hook_entity_translation_create()
1246 */
1247function hook_ENTITY_TYPE_translation_create(\Drupal\Core\Entity\EntityInterface $translation) {
1248  \Drupal::logger('example')->info('ENTITY_TYPE translation created: @label', ['@label' => $translation->label()]);
1249}
1250
1251/**
1252 * Respond to creation of a new entity translation.
1253 *
1254 * This hook runs once the entity translation has been stored. Note that hook
1255 * implementations may not alter the stored entity translation data.
1256 *
1257 * @param \Drupal\Core\Entity\EntityInterface $translation
1258 *   The entity object of the translation just stored.
1259 *
1260 * @ingroup entity_crud
1261 * @see hook_ENTITY_TYPE_translation_insert()
1262 */
1263function hook_entity_translation_insert(\Drupal\Core\Entity\EntityInterface $translation) {
1264  $variables = [
1265    '@language' => $translation->language()->getName(),
1266    '@label' => $translation->getUntranslated()->label(),
1267  ];
1268  \Drupal::logger('example')->notice('The @language translation of @label has just been stored.', $variables);
1269}
1270
1271/**
1272 * Respond to creation of a new entity translation of a particular type.
1273 *
1274 * This hook runs once the entity translation has been stored. Note that hook
1275 * implementations may not alter the stored entity translation data.
1276 *
1277 * @param \Drupal\Core\Entity\EntityInterface $translation
1278 *   The entity object of the translation just stored.
1279 *
1280 * @ingroup entity_crud
1281 * @see hook_entity_translation_insert()
1282 */
1283function hook_ENTITY_TYPE_translation_insert(\Drupal\Core\Entity\EntityInterface $translation) {
1284  $variables = [
1285    '@language' => $translation->language()->getName(),
1286    '@label' => $translation->getUntranslated()->label(),
1287  ];
1288  \Drupal::logger('example')->notice('The @language translation of @label has just been stored.', $variables);
1289}
1290
1291/**
1292 * Respond to entity translation deletion.
1293 *
1294 * This hook runs once the entity translation has been deleted from storage.
1295 *
1296 * @param \Drupal\Core\Entity\EntityInterface $translation
1297 *   The original entity object.
1298 *
1299 * @ingroup entity_crud
1300 * @see hook_ENTITY_TYPE_translation_delete()
1301 */
1302function hook_entity_translation_delete(\Drupal\Core\Entity\EntityInterface $translation) {
1303  $variables = [
1304    '@language' => $translation->language()->getName(),
1305    '@label' => $translation->label(),
1306  ];
1307  \Drupal::logger('example')->notice('The @language translation of @label has just been deleted.', $variables);
1308}
1309
1310/**
1311 * Respond to entity translation deletion of a particular type.
1312 *
1313 * This hook runs once the entity translation has been deleted from storage.
1314 *
1315 * @param \Drupal\Core\Entity\EntityInterface $translation
1316 *   The original entity object.
1317 *
1318 * @ingroup entity_crud
1319 * @see hook_entity_translation_delete()
1320 */
1321function hook_ENTITY_TYPE_translation_delete(\Drupal\Core\Entity\EntityInterface $translation) {
1322  $variables = [
1323    '@language' => $translation->language()->getName(),
1324    '@label' => $translation->label(),
1325  ];
1326  \Drupal::logger('example')->notice('The @language translation of @label has just been deleted.', $variables);
1327}
1328
1329/**
1330 * Act before entity deletion.
1331 *
1332 * @param \Drupal\Core\Entity\EntityInterface $entity
1333 *   The entity object for the entity that is about to be deleted.
1334 *
1335 * @ingroup entity_crud
1336 * @see hook_ENTITY_TYPE_predelete()
1337 */
1338function hook_entity_predelete(\Drupal\Core\Entity\EntityInterface $entity) {
1339  $connection = \Drupal::database();
1340  // Count references to this entity in a custom table before they are removed
1341  // upon entity deletion.
1342  $id = $entity->id();
1343  $type = $entity->getEntityTypeId();
1344  $count = \Drupal::database()->select('example_entity_data')
1345    ->condition('type', $type)
1346    ->condition('id', $id)
1347    ->countQuery()
1348    ->execute()
1349    ->fetchField();
1350
1351  // Log the count in a table that records this statistic for deleted entities.
1352  $connection->merge('example_deleted_entity_statistics')
1353    ->key(['type' => $type, 'id' => $id])
1354    ->fields(['count' => $count])
1355    ->execute();
1356}
1357
1358/**
1359 * Act before entity deletion of a particular entity type.
1360 *
1361 * @param \Drupal\Core\Entity\EntityInterface $entity
1362 *   The entity object for the entity that is about to be deleted.
1363 *
1364 * @ingroup entity_crud
1365 * @see hook_entity_predelete()
1366 */
1367function hook_ENTITY_TYPE_predelete(\Drupal\Core\Entity\EntityInterface $entity) {
1368  $connection = \Drupal::database();
1369  // Count references to this entity in a custom table before they are removed
1370  // upon entity deletion.
1371  $id = $entity->id();
1372  $type = $entity->getEntityTypeId();
1373  $count = \Drupal::database()->select('example_entity_data')
1374    ->condition('type', $type)
1375    ->condition('id', $id)
1376    ->countQuery()
1377    ->execute()
1378    ->fetchField();
1379
1380  // Log the count in a table that records this statistic for deleted entities.
1381  $connection->merge('example_deleted_entity_statistics')
1382    ->key(['type' => $type, 'id' => $id])
1383    ->fields(['count' => $count])
1384    ->execute();
1385}
1386
1387/**
1388 * Respond to entity deletion.
1389 *
1390 * This hook runs once the entity has been deleted from the storage.
1391 *
1392 * @param \Drupal\Core\Entity\EntityInterface $entity
1393 *   The entity object for the entity that has been deleted.
1394 *
1395 * @ingroup entity_crud
1396 * @see hook_ENTITY_TYPE_delete()
1397 */
1398function hook_entity_delete(\Drupal\Core\Entity\EntityInterface $entity) {
1399  // Delete the entity's entry from a fictional table of all entities.
1400  \Drupal::database()->delete('example_entity')
1401    ->condition('type', $entity->getEntityTypeId())
1402    ->condition('id', $entity->id())
1403    ->execute();
1404}
1405
1406/**
1407 * Respond to entity deletion of a particular type.
1408 *
1409 * This hook runs once the entity has been deleted from the storage.
1410 *
1411 * @param \Drupal\Core\Entity\EntityInterface $entity
1412 *   The entity object for the entity that has been deleted.
1413 *
1414 * @ingroup entity_crud
1415 * @see hook_entity_delete()
1416 */
1417function hook_ENTITY_TYPE_delete(\Drupal\Core\Entity\EntityInterface $entity) {
1418  // Delete the entity's entry from a fictional table of all entities.
1419  \Drupal::database()->delete('example_entity')
1420    ->condition('type', $entity->getEntityTypeId())
1421    ->condition('id', $entity->id())
1422    ->execute();
1423}
1424
1425/**
1426 * Respond to entity revision deletion.
1427 *
1428 * This hook runs once the entity revision has been deleted from the storage.
1429 *
1430 * @param \Drupal\Core\Entity\EntityInterface $entity
1431 *   The entity object for the entity revision that has been deleted.
1432 *
1433 * @ingroup entity_crud
1434 * @see hook_ENTITY_TYPE_revision_delete()
1435 */
1436function hook_entity_revision_delete(\Drupal\Core\Entity\EntityInterface $entity) {
1437  $referenced_files_by_field = _editor_get_file_uuids_by_field($entity);
1438  foreach ($referenced_files_by_field as $field => $uuids) {
1439    _editor_delete_file_usage($uuids, $entity, 1);
1440  }
1441}
1442
1443/**
1444 * Respond to entity revision deletion of a particular type.
1445 *
1446 * This hook runs once the entity revision has been deleted from the storage.
1447 *
1448 * @param \Drupal\Core\Entity\EntityInterface $entity
1449 *   The entity object for the entity revision that has been deleted.
1450 *
1451 * @ingroup entity_crud
1452 * @see hook_entity_revision_delete()
1453 */
1454function hook_ENTITY_TYPE_revision_delete(\Drupal\Core\Entity\EntityInterface $entity) {
1455  $referenced_files_by_field = _editor_get_file_uuids_by_field($entity);
1456  foreach ($referenced_files_by_field as $field => $uuids) {
1457    _editor_delete_file_usage($uuids, $entity, 1);
1458  }
1459}
1460
1461/**
1462 * Act on entities being assembled before rendering.
1463 *
1464 * @param &$build
1465 *   A renderable array representing the entity content. The module may add
1466 *   elements to $build prior to rendering. The structure of $build is a
1467 *   renderable array as expected by
1468 *   \Drupal\Core\Render\RendererInterface::render().
1469 * @param \Drupal\Core\Entity\EntityInterface $entity
1470 *   The entity object.
1471 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
1472 *   The entity view display holding the display options configured for the
1473 *   entity components.
1474 * @param $view_mode
1475 *   The view mode the entity is rendered in.
1476 *
1477 * @see hook_entity_view_alter()
1478 * @see hook_ENTITY_TYPE_view()
1479 *
1480 * @ingroup entity_crud
1481 */
1482function hook_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode) {
1483  // Only do the extra work if the component is configured to be displayed.
1484  // This assumes a 'mymodule_addition' extra field has been defined for the
1485  // entity bundle in hook_entity_extra_field_info().
1486  if ($display->getComponent('mymodule_addition')) {
1487    $build['mymodule_addition'] = [
1488      '#markup' => mymodule_addition($entity),
1489      '#theme' => 'mymodule_my_additional_field',
1490    ];
1491  }
1492}
1493
1494/**
1495 * Act on entities of a particular type being assembled before rendering.
1496 *
1497 * @param &$build
1498 *   A renderable array representing the entity content. The module may add
1499 *   elements to $build prior to rendering. The structure of $build is a
1500 *   renderable array as expected by
1501 *   \Drupal\Core\Render\RendererInterface::render().
1502 * @param \Drupal\Core\Entity\EntityInterface $entity
1503 *   The entity object.
1504 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
1505 *   The entity view display holding the display options configured for the
1506 *   entity components.
1507 * @param $view_mode
1508 *   The view mode the entity is rendered in.
1509 *
1510 * @see hook_ENTITY_TYPE_view_alter()
1511 * @see hook_entity_view()
1512 *
1513 * @ingroup entity_crud
1514 */
1515function hook_ENTITY_TYPE_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode) {
1516  // Only do the extra work if the component is configured to be displayed.
1517  // This assumes a 'mymodule_addition' extra field has been defined for the
1518  // entity bundle in hook_entity_extra_field_info().
1519  if ($display->getComponent('mymodule_addition')) {
1520    $build['mymodule_addition'] = [
1521      '#markup' => mymodule_addition($entity),
1522      '#theme' => 'mymodule_my_additional_field',
1523    ];
1524  }
1525}
1526
1527/**
1528 * Alter the results of the entity build array.
1529 *
1530 * This hook is called after the content has been assembled in a structured
1531 * array and may be used for doing processing which requires that the complete
1532 * entity content structure has been built.
1533 *
1534 * If a module wishes to act on the rendered HTML of the entity rather than the
1535 * structured content array, it may use this hook to add a #post_render
1536 * callback. Alternatively, it could also implement hook_preprocess_HOOK() for
1537 * the particular entity type template, if there is one (e.g., node.html.twig).
1538 *
1539 * See the @link themeable Default theme implementations topic @endlink and
1540 * \Drupal\Core\Render\RendererInterface::render() for details.
1541 *
1542 * @param array &$build
1543 *   A renderable array representing the entity content.
1544 * @param \Drupal\Core\Entity\EntityInterface $entity
1545 *   The entity object being rendered.
1546 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
1547 *   The entity view display holding the display options configured for the
1548 *   entity components.
1549 *
1550 * @ingroup entity_crud
1551 *
1552 * @see hook_entity_view()
1553 * @see hook_ENTITY_TYPE_view_alter()
1554 */
1555function hook_entity_view_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
1556  if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
1557    // Change its weight.
1558    $build['an_additional_field']['#weight'] = -10;
1559
1560    // Add a #post_render callback to act on the rendered HTML of the entity.
1561    // The object must implement \Drupal\Core\Security\TrustedCallbackInterface.
1562    $build['#post_render'][] = '\Drupal\my_module\NodeCallback::postRender';
1563  }
1564}
1565
1566/**
1567 * Alter the results of the entity build array for a particular entity type.
1568 *
1569 * This hook is called after the content has been assembled in a structured
1570 * array and may be used for doing processing which requires that the complete
1571 * entity content structure has been built.
1572 *
1573 * If a module wishes to act on the rendered HTML of the entity rather than the
1574 * structured content array, it may use this hook to add a #post_render
1575 * callback. Alternatively, it could also implement hook_preprocess_HOOK() for
1576 * the particular entity type template, if there is one (e.g., node.html.twig).
1577 *
1578 * See the @link themeable Default theme implementations topic @endlink and
1579 * \Drupal\Core\Render\RendererInterface::render() for details.
1580 *
1581 * @param array &$build
1582 *   A renderable array representing the entity content.
1583 * @param \Drupal\Core\Entity\EntityInterface $entity
1584 *   The entity object being rendered.
1585 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
1586 *   The entity view display holding the display options configured for the
1587 *   entity components.
1588 *
1589 * @ingroup entity_crud
1590 *
1591 * @see hook_ENTITY_TYPE_view()
1592 * @see hook_entity_view_alter()
1593 */
1594function hook_ENTITY_TYPE_view_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
1595  if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
1596    // Change its weight.
1597    $build['an_additional_field']['#weight'] = -10;
1598
1599    // Add a #post_render callback to act on the rendered HTML of the entity.
1600    $build['#post_render'][] = 'my_module_node_post_render';
1601  }
1602}
1603
1604/**
1605 * Act on entities as they are being prepared for view.
1606 *
1607 * Allows you to operate on multiple entities as they are being prepared for
1608 * view. Only use this if attaching the data during the entity loading phase
1609 * is not appropriate, for example when attaching other 'entity' style objects.
1610 *
1611 * @param string $entity_type_id
1612 *   The type of entities being viewed (i.e. node, user, comment).
1613 * @param array $entities
1614 *   The entities keyed by entity ID.
1615 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface[] $displays
1616 *   The array of entity view displays holding the display options configured
1617 *   for the entity components, keyed by bundle name.
1618 * @param string $view_mode
1619 *   The view mode.
1620 *
1621 * @ingroup entity_crud
1622 */
1623function hook_entity_prepare_view($entity_type_id, array $entities, array $displays, $view_mode) {
1624  // Load a specific node into the user object for later theming.
1625  if (!empty($entities) && $entity_type_id == 'user') {
1626    // Only do the extra work if the component is configured to be
1627    // displayed. This assumes a 'mymodule_addition' extra field has been
1628    // defined for the entity bundle in hook_entity_extra_field_info().
1629    $ids = [];
1630    foreach ($entities as $id => $entity) {
1631      if ($displays[$entity->bundle()]->getComponent('mymodule_addition')) {
1632        $ids[] = $id;
1633      }
1634    }
1635    if ($ids) {
1636      $nodes = mymodule_get_user_nodes($ids);
1637      foreach ($ids as $id) {
1638        $entities[$id]->user_node = $nodes[$id];
1639      }
1640    }
1641  }
1642}
1643
1644/**
1645 * Change the view mode of an entity that is being displayed.
1646 *
1647 * @param string $view_mode
1648 *   The view_mode that is to be used to display the entity.
1649 * @param \Drupal\Core\Entity\EntityInterface $entity
1650 *   The entity that is being viewed.
1651 *
1652 * @ingroup entity_crud
1653 */
1654function hook_entity_view_mode_alter(&$view_mode, \Drupal\Core\Entity\EntityInterface $entity) {
1655  // For nodes, change the view mode when it is teaser.
1656  if ($entity->getEntityTypeId() == 'node' && $view_mode == 'teaser') {
1657    $view_mode = 'my_custom_view_mode';
1658  }
1659}
1660
1661/**
1662 * Alter entity renderable values before cache checking during rendering.
1663 *
1664 * Invoked for a specific entity type.
1665 *
1666 * The values in the #cache key of the renderable array are used to determine if
1667 * a cache entry exists for the entity's rendered output. Ideally only values
1668 * that pertain to caching should be altered in this hook.
1669 *
1670 * @param array &$build
1671 *   A renderable array containing the entity's caching and view mode values.
1672 * @param \Drupal\Core\Entity\EntityInterface $entity
1673 *   The entity that is being viewed.
1674 * @param string $view_mode
1675 *   The view_mode that is to be used to display the entity.
1676 *
1677 * @see \Drupal\Core\Render\RendererInterface::render()
1678 * @see \Drupal\Core\Entity\EntityViewBuilder
1679 * @see hook_entity_build_defaults_alter()
1680 *
1681 * @ingroup entity_crud
1682 */
1683function hook_ENTITY_TYPE_build_defaults_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, $view_mode) {
1684
1685}
1686
1687/**
1688 * Alter entity renderable values before cache checking during rendering.
1689 *
1690 * The values in the #cache key of the renderable array are used to determine if
1691 * a cache entry exists for the entity's rendered output. Ideally only values
1692 * that pertain to caching should be altered in this hook.
1693 *
1694 * @param array &$build
1695 *   A renderable array containing the entity's caching and view mode values.
1696 * @param \Drupal\Core\Entity\EntityInterface $entity
1697 *   The entity that is being viewed.
1698 * @param string $view_mode
1699 *   The view_mode that is to be used to display the entity.
1700 *
1701 * @see \Drupal\Core\Render\RendererInterface::render()
1702 * @see \Drupal\Core\Entity\EntityViewBuilder
1703 * @see hook_ENTITY_TYPE_build_defaults_alter()
1704 *
1705 * @ingroup entity_crud
1706 */
1707function hook_entity_build_defaults_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, $view_mode) {
1708
1709}
1710
1711/**
1712 * Alter the settings used for displaying an entity.
1713 *
1714 * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
1715 *   The entity view display that will be used to display the entity
1716 *   components.
1717 * @param array $context
1718 *   An associative array containing:
1719 *   - entity_type: The entity type, e.g., 'node' or 'user'.
1720 *   - bundle: The bundle, e.g., 'page' or 'article'.
1721 *   - view_mode: The view mode, e.g., 'full', 'teaser', etc.
1722 *
1723 * @ingroup entity_crud
1724 */
1725function hook_entity_view_display_alter(\Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, array $context) {
1726  // Leave field labels out of the search index.
1727  if ($context['entity_type'] == 'node' && $context['view_mode'] == 'search_index') {
1728    foreach ($display->getComponents() as $name => $options) {
1729      if (isset($options['label'])) {
1730        $options['label'] = 'hidden';
1731        $display->setComponent($name, $options);
1732      }
1733    }
1734  }
1735}
1736
1737/**
1738 * Alter the render array generated by an EntityDisplay for an entity.
1739 *
1740 * @param array $build
1741 *   The renderable array generated by the EntityDisplay.
1742 * @param array $context
1743 *   An associative array containing:
1744 *   - entity: The entity being rendered.
1745 *   - view_mode: The view mode; for example, 'full' or 'teaser'.
1746 *   - display: The EntityDisplay holding the display options.
1747 *
1748 * @ingroup entity_crud
1749 */
1750function hook_entity_display_build_alter(&$build, $context) {
1751  // Append RDF term mappings on displayed taxonomy links.
1752  foreach (Element::children($build) as $field_name) {
1753    $element = &$build[$field_name];
1754    if ($element['#field_type'] == 'entity_reference' && $element['#formatter'] == 'entity_reference_label') {
1755      foreach ($element['#items'] as $delta => $item) {
1756        $term = $item->entity;
1757        if (!empty($term->rdf_mapping['rdftype'])) {
1758          $element[$delta]['#options']['attributes']['typeof'] = $term->rdf_mapping['rdftype'];
1759        }
1760        if (!empty($term->rdf_mapping['name']['predicates'])) {
1761          $element[$delta]['#options']['attributes']['property'] = $term->rdf_mapping['name']['predicates'];
1762        }
1763      }
1764    }
1765  }
1766}
1767
1768/**
1769 * Acts on an entity object about to be shown on an entity form.
1770 *
1771 * This can be typically used to pre-fill entity values or change the form state
1772 * before the entity form is built. It is invoked just once when first building
1773 * the entity form. Rebuilds will not trigger a new invocation.
1774 *
1775 * @param \Drupal\Core\Entity\EntityInterface $entity
1776 *   The entity that is about to be shown on the form.
1777 * @param $operation
1778 *   The current operation.
1779 * @param \Drupal\Core\Form\FormStateInterface $form_state
1780 *   The current state of the form.
1781 *
1782 * @see \Drupal\Core\Entity\EntityForm::prepareEntity()
1783 * @see hook_ENTITY_TYPE_prepare_form()
1784 *
1785 * @ingroup entity_crud
1786 */
1787function hook_entity_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Form\FormStateInterface $form_state) {
1788  if ($operation == 'edit') {
1789    $entity->label->value = 'Altered label';
1790    $form_state->set('label_altered', TRUE);
1791  }
1792}
1793
1794/**
1795 * Acts on a particular type of entity object about to be in an entity form.
1796 *
1797 * This can be typically used to pre-fill entity values or change the form state
1798 * before the entity form is built. It is invoked just once when first building
1799 * the entity form. Rebuilds will not trigger a new invocation.
1800 *
1801 * @param \Drupal\Core\Entity\EntityInterface $entity
1802 *   The entity that is about to be shown on the form.
1803 * @param $operation
1804 *   The current operation.
1805 * @param \Drupal\Core\Form\FormStateInterface $form_state
1806 *   The current state of the form.
1807 *
1808 * @see \Drupal\Core\Entity\EntityForm::prepareEntity()
1809 * @see hook_entity_prepare_form()
1810 *
1811 * @ingroup entity_crud
1812 */
1813function hook_ENTITY_TYPE_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Form\FormStateInterface $form_state) {
1814  if ($operation == 'edit') {
1815    $entity->label->value = 'Altered label';
1816    $form_state->set('label_altered', TRUE);
1817  }
1818}
1819
1820/**
1821 * Change the form mode used to build an entity form.
1822 *
1823 * @param string $form_mode
1824 *   The form_mode that is to be used to build the entity form.
1825 * @param \Drupal\Core\Entity\EntityInterface $entity
1826 *   The entity for which the form is being built.
1827 *
1828 * @ingroup entity_crud
1829 */
1830function hook_entity_form_mode_alter(&$form_mode, \Drupal\Core\Entity\EntityInterface $entity) {
1831  // Change the form mode for users with Administrator role.
1832  if ($entity->getEntityTypeId() == 'user' && $entity->hasRole('administrator')) {
1833    $form_mode = 'my_custom_form_mode';
1834  }
1835}
1836
1837/**
1838 * Alter the settings used for displaying an entity form.
1839 *
1840 * @param \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display
1841 *   The entity_form_display object that will be used to display the entity form
1842 *   components.
1843 * @param array $context
1844 *   An associative array containing:
1845 *   - entity_type: The entity type, e.g., 'node' or 'user'.
1846 *   - bundle: The bundle, e.g., 'page' or 'article'.
1847 *   - form_mode: The form mode; e.g., 'default', 'profile', 'register', etc.
1848 *
1849 * @ingroup entity_crud
1850 */
1851function hook_entity_form_display_alter(\Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display, array $context) {
1852  // Hide the 'user_picture' field from the register form.
1853  if ($context['entity_type'] == 'user' && $context['form_mode'] == 'register') {
1854    $form_display->setComponent('user_picture', [
1855      'region' => 'hidden',
1856    ]);
1857  }
1858}
1859
1860/**
1861 * Provides custom base field definitions for a content entity type.
1862 *
1863 * Field (storage) definitions returned by this hook must run through the
1864 * regular field storage life-cycle operations: they need to be properly
1865 * installed, updated, and uninstalled. This would typically be done through the
1866 * Entity Update API provided by the entity definition update manager.
1867 *
1868 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
1869 *   The entity type definition.
1870 *
1871 * @return \Drupal\Core\Field\FieldDefinitionInterface[]
1872 *   An array of field definitions, keyed by field name.
1873 *
1874 * @see hook_entity_base_field_info_alter()
1875 * @see hook_entity_bundle_field_info()
1876 * @see hook_entity_bundle_field_info_alter()
1877 * @see \Drupal\Core\Field\FieldDefinitionInterface
1878 * @see \Drupal\Core\Entity\EntityFieldManagerInterface::getFieldDefinitions()
1879 * @see \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface
1880 * @see https://www.drupal.org/node/3034742
1881 */
1882function hook_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) {
1883  if ($entity_type->id() == 'node') {
1884    $fields = [];
1885    $fields['mymodule_text'] = BaseFieldDefinition::create('string')
1886      ->setLabel(t('The text'))
1887      ->setDescription(t('A text property added by mymodule.'))
1888      ->setComputed(TRUE)
1889      ->setClass('\Drupal\mymodule\EntityComputedText');
1890
1891    return $fields;
1892  }
1893}
1894
1895/**
1896 * Alter base field definitions for a content entity type.
1897 *
1898 * @param \Drupal\Core\Field\FieldDefinitionInterface[] $fields
1899 *   The array of base field definitions for the entity type.
1900 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
1901 *   The entity type definition.
1902 *
1903 * @see hook_entity_base_field_info()
1904 * @see hook_entity_bundle_field_info()
1905 * @see hook_entity_bundle_field_info_alter()
1906 *
1907 * @todo WARNING: This hook will be changed in
1908 * https://www.drupal.org/node/2346329.
1909 */
1910function hook_entity_base_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type) {
1911  // Alter the mymodule_text field to use a custom class.
1912  if ($entity_type->id() == 'node' && !empty($fields['mymodule_text'])) {
1913    $fields['mymodule_text']->setClass('\Drupal\anothermodule\EntityComputedText');
1914  }
1915}
1916
1917/**
1918 * Provides field definitions for a specific bundle within an entity type.
1919 *
1920 * Bundle fields either have to override an existing base field, or need to
1921 * provide a field storage definition via hook_entity_field_storage_info()
1922 * unless they are computed.
1923 *
1924 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
1925 *   The entity type definition.
1926 * @param string $bundle
1927 *   The bundle.
1928 * @param \Drupal\Core\Field\FieldDefinitionInterface[] $base_field_definitions
1929 *   The list of base field definitions for the entity type.
1930 *
1931 * @return \Drupal\Core\Field\FieldDefinitionInterface[]
1932 *   An array of bundle field definitions, keyed by field name.
1933 *
1934 * @see hook_entity_base_field_info()
1935 * @see hook_entity_base_field_info_alter()
1936 * @see hook_entity_field_storage_info()
1937 * @see hook_entity_field_storage_info_alter()
1938 * @see hook_entity_bundle_field_info_alter()
1939 * @see \Drupal\Core\Field\FieldDefinitionInterface
1940 * @see \Drupal\Core\Field\FieldDefinition
1941 * @see \Drupal\Core\Entity\EntityFieldManagerInterface::getFieldDefinitions()
1942 *
1943 * @todo WARNING: This hook will be changed in
1944 * https://www.drupal.org/node/2346347.
1945 */
1946function hook_entity_bundle_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
1947  // Add a property only to nodes of the 'article' bundle.
1948  if ($entity_type->id() == 'node' && $bundle == 'article') {
1949    $fields = [];
1950    $storage_definitions = mymodule_entity_field_storage_info($entity_type);
1951    $fields['mymodule_bundle_field'] = FieldDefinition::createFromFieldStorageDefinition($storage_definitions['mymodule_bundle_field'])
1952      ->setLabel(t('Bundle Field'));
1953    return $fields;
1954  }
1955
1956}
1957
1958/**
1959 * Alter bundle field definitions.
1960 *
1961 * @param \Drupal\Core\Field\FieldDefinitionInterface[] $fields
1962 *   The array of bundle field definitions.
1963 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
1964 *   The entity type definition.
1965 * @param string $bundle
1966 *   The bundle.
1967 *
1968 * @see hook_entity_base_field_info()
1969 * @see hook_entity_base_field_info_alter()
1970 * @see hook_entity_bundle_field_info()
1971 *
1972 * @todo WARNING: This hook will be changed in
1973 * https://www.drupal.org/node/2346347.
1974 */
1975function hook_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) {
1976  if ($entity_type->id() == 'node' && $bundle == 'article' && !empty($fields['mymodule_text'])) {
1977    // Alter the mymodule_text field to use a custom class.
1978    $fields['mymodule_text']->setClass('\Drupal\anothermodule\EntityComputedText');
1979  }
1980}
1981
1982/**
1983 * Provides field storage definitions for a content entity type.
1984 *
1985 * Field storage definitions returned by this hook must run through the regular
1986 * field storage life-cycle operations: they need to be properly installed,
1987 * updated, and uninstalled. This would typically be done through the Entity
1988 * Update API provided by the entity definition update manager.
1989 *
1990 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
1991 *   The entity type definition.
1992 *
1993 * @return \Drupal\Core\Field\FieldStorageDefinitionInterface[]
1994 *   An array of field storage definitions, keyed by field name.
1995 *
1996 * @see hook_entity_field_storage_info_alter()
1997 * @see \Drupal\Core\Field\FieldStorageDefinitionInterface
1998 * @see \Drupal\Core\Entity\EntityFieldManagerInterface::getFieldStorageDefinitions()
1999 * @see \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface
2000 * @see https://www.drupal.org/node/3034742
2001 */
2002function hook_entity_field_storage_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) {
2003  if (\Drupal::entityTypeManager()->getStorage($entity_type->id()) instanceof DynamicallyFieldableEntityStorageInterface) {
2004    // Query by filtering on the ID as this is more efficient than filtering
2005    // on the entity_type property directly.
2006    $ids = \Drupal::entityQuery('field_storage_config')
2007      ->condition('id', $entity_type->id() . '.', 'STARTS_WITH')
2008      ->execute();
2009    // Fetch all fields and key them by field name.
2010    $field_storages = FieldStorageConfig::loadMultiple($ids);
2011    $result = [];
2012    foreach ($field_storages as $field_storage) {
2013      $result[$field_storage->getName()] = $field_storage;
2014    }
2015
2016    return $result;
2017  }
2018}
2019
2020/**
2021 * Alter field storage definitions for a content entity type.
2022 *
2023 * @param \Drupal\Core\Field\FieldStorageDefinitionInterface[] $fields
2024 *   The array of field storage definitions for the entity type.
2025 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
2026 *   The entity type definition.
2027 *
2028 * @see hook_entity_field_storage_info()
2029 */
2030function hook_entity_field_storage_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type) {
2031  // Alter the max_length setting.
2032  if ($entity_type->id() == 'node' && !empty($fields['mymodule_text'])) {
2033    $fields['mymodule_text']->setSetting('max_length', 128);
2034  }
2035}
2036
2037/**
2038 * Declares entity operations.
2039 *
2040 * @param \Drupal\Core\Entity\EntityInterface $entity
2041 *   The entity on which the linked operations will be performed.
2042 *
2043 * @return array
2044 *   An operations array as returned by
2045 *   EntityListBuilderInterface::getOperations().
2046 *
2047 * @see \Drupal\Core\Entity\EntityListBuilderInterface::getOperations()
2048 */
2049function hook_entity_operation(\Drupal\Core\Entity\EntityInterface $entity) {
2050  $operations = [];
2051  $operations['translate'] = [
2052    'title' => t('Translate'),
2053    'url' => \Drupal\Core\Url::fromRoute('foo_module.entity.translate'),
2054    'weight' => 50,
2055  ];
2056
2057  return $operations;
2058}
2059
2060/**
2061 * Alter entity operations.
2062 *
2063 * @param array $operations
2064 *   Operations array as returned by
2065 *   \Drupal\Core\Entity\EntityListBuilderInterface::getOperations().
2066 * @param \Drupal\Core\Entity\EntityInterface $entity
2067 *   The entity on which the linked operations will be performed.
2068 */
2069function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\EntityInterface $entity) {
2070  // Alter the title and weight.
2071  $operations['translate']['title'] = t('Translate @entity_type', [
2072    '@entity_type' => $entity->getEntityTypeId(),
2073  ]);
2074  $operations['translate']['weight'] = 99;
2075}
2076
2077/**
2078 * Control access to fields.
2079 *
2080 * This hook is invoked from
2081 * \Drupal\Core\Entity\EntityAccessControlHandler::fieldAccess() to let modules
2082 * grant or deny operations on fields.
2083 *
2084 * @param string $operation
2085 *   The operation to be performed. See
2086 *   \Drupal\Core\Entity\EntityAccessControlHandlerInterface::fieldAccess()
2087 *   for possible values.
2088 * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
2089 *   The field definition.
2090 * @param \Drupal\Core\Session\AccountInterface $account
2091 *   The user account to check.
2092 * @param \Drupal\Core\Field\FieldItemListInterface $items
2093 *   (optional) The entity field object for which to check access, or NULL if
2094 *   access is checked for the field definition, without any specific value
2095 *   available. Defaults to NULL.
2096 *
2097 * @return \Drupal\Core\Access\AccessResultInterface
2098 *   The access result.
2099 *
2100 * @see \Drupal\Core\Entity\EntityAccessControlHandlerInterface::fieldAccess()
2101 */
2102function hook_entity_field_access($operation, \Drupal\Core\Field\FieldDefinitionInterface $field_definition, \Drupal\Core\Session\AccountInterface $account, \Drupal\Core\Field\FieldItemListInterface $items = NULL) {
2103  if ($field_definition->getName() == 'field_of_interest' && $operation == 'edit') {
2104    return AccessResult::allowedIfHasPermission($account, 'update field of interest');
2105  }
2106  return AccessResult::neutral();
2107}
2108
2109/**
2110 * Alter the default access behavior for a given field.
2111 *
2112 * Use this hook to override access grants from another module. Note that the
2113 * original default access flag is masked under the ':default' key.
2114 *
2115 * @param \Drupal\Core\Access\AccessResultInterface[] $grants
2116 *   An array of grants gathered by hook_entity_field_access(). The array is
2117 *   keyed by the module that defines the field's access control; the values are
2118 *   grant responses for each module (\Drupal\Core\Access\AccessResult).
2119 * @param array $context
2120 *   Context array on the performed operation with the following keys:
2121 *   - operation: The operation to be performed (string).
2122 *   - field_definition: The field definition object
2123 *     (\Drupal\Core\Field\FieldDefinitionInterface)
2124 *   - account: The user account to check access for
2125 *     (Drupal\user\Entity\User).
2126 *   - items: (optional) The entity field items
2127 *     (\Drupal\Core\Field\FieldItemListInterface).
2128 */
2129function hook_entity_field_access_alter(array &$grants, array $context) {
2130  /** @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */
2131  $field_definition = $context['field_definition'];
2132  if ($field_definition->getName() == 'field_of_interest' && $grants['node']->isForbidden()) {
2133    // Override node module's restriction to no opinion (neither allowed nor
2134    // forbidden). We don't want to provide our own access hook, we only want to
2135    // take out node module's part in the access handling of this field. We also
2136    // don't want to switch node module's grant to
2137    // AccessResultInterface::isAllowed() , because the grants of other modules
2138    // should still decide on their own if this field is accessible or not
2139    $grants['node'] = AccessResult::neutral()->inheritCacheability($grants['node']);
2140  }
2141}
2142
2143/**
2144 * Acts when initializing a fieldable entity object.
2145 *
2146 * This hook runs after a new entity object or a new entity translation object
2147 * has just been instantiated. It can be used to set initial values, e.g. to
2148 * provide defaults.
2149 *
2150 * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
2151 *   The entity object.
2152 *
2153 * @ingroup entity_crud
2154 * @see hook_ENTITY_TYPE_field_values_init()
2155 */
2156function hook_entity_field_values_init(\Drupal\Core\Entity\FieldableEntityInterface $entity) {
2157  if ($entity instanceof \Drupal\Core\Entity\ContentEntityInterface && !$entity->foo->value) {
2158    $entity->foo->value = 'some_initial_value';
2159  }
2160}
2161
2162/**
2163 * Acts when initializing a fieldable entity object.
2164 *
2165 * This hook runs after a new entity object or a new entity translation object
2166 * has just been instantiated. It can be used to set initial values, e.g. to
2167 * provide defaults.
2168 *
2169 * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
2170 *   The entity object.
2171 *
2172 * @ingroup entity_crud
2173 * @see hook_entity_field_values_init()
2174 */
2175function hook_ENTITY_TYPE_field_values_init(\Drupal\Core\Entity\FieldableEntityInterface $entity) {
2176  if (!$entity->foo->value) {
2177    $entity->foo->value = 'some_initial_value';
2178  }
2179}
2180
2181/**
2182 * Exposes "pseudo-field" components on content entities.
2183 *
2184 * Field UI's "Manage fields" and "Manage display" pages let users re-order
2185 * fields, but also non-field components. For nodes, these include elements
2186 * exposed by modules through hook_form_alter(), for instance.
2187 *
2188 * Content entities or modules that want to have their components supported
2189 * should expose them using this hook. The user-defined settings (weight,
2190 * visible) are automatically applied when entities or entity forms are
2191 * rendered.
2192 *
2193 * @see hook_entity_extra_field_info_alter()
2194 *
2195 * @return array
2196 *   The array structure is identical to that of the return value of
2197 *   \Drupal\Core\Entity\EntityFieldManagerInterface::getExtraFields().
2198 */
2199function hook_entity_extra_field_info() {
2200  $extra = [];
2201  $module_language_enabled = \Drupal::moduleHandler()->moduleExists('language');
2202  $description = t('Node module element');
2203
2204  foreach (NodeType::loadMultiple() as $bundle) {
2205
2206    // Add also the 'language' select if Language module is enabled and the
2207    // bundle has multilingual support.
2208    // Visibility of the ordering of the language selector is the same as on the
2209    // node/add form.
2210    if ($module_language_enabled) {
2211      $configuration = ContentLanguageSettings::loadByEntityTypeBundle('node', $bundle->id());
2212      if ($configuration->isLanguageAlterable()) {
2213        $extra['node'][$bundle->id()]['form']['language'] = [
2214          'label' => t('Language'),
2215          'description' => $description,
2216          'weight' => 0,
2217        ];
2218      }
2219    }
2220    $extra['node'][$bundle->id()]['display']['language'] = [
2221      'label' => t('Language'),
2222      'description' => $description,
2223      'weight' => 0,
2224      'visible' => FALSE,
2225    ];
2226  }
2227
2228  return $extra;
2229}
2230
2231/**
2232 * Alter "pseudo-field" components on content entities.
2233 *
2234 * @param array $info
2235 *   The array structure is identical to that of the return value of
2236 *   \Drupal\Core\Entity\EntityFieldManagerInterface::getExtraFields().
2237 *
2238 * @see hook_entity_extra_field_info()
2239 */
2240function hook_entity_extra_field_info_alter(&$info) {
2241  // Force node title to always be at the top of the list by default.
2242  foreach (NodeType::loadMultiple() as $bundle) {
2243    if (isset($info['node'][$bundle->id()]['form']['title'])) {
2244      $info['node'][$bundle->id()]['form']['title']['weight'] = -20;
2245    }
2246  }
2247}
2248
2249/**
2250 * @} End of "addtogroup hooks".
2251 */
2252