entity.api.php 82 KB

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