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