Mercurial > hg > isophonics-drupal-site
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 */ |