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