comparison core/lib/Drupal/Core/Entity/entity.api.php @ 0:4c8ae668cc8c

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