entity.api.php 88 KB

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