1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113 |
- <?php
- /**
- * @file
- * Hooks and documentation related to entities.
- */
- use Drupal\Core\Access\AccessResult;
- use Drupal\Core\Entity\ContentEntityInterface;
- use Drupal\Core\Entity\DynamicallyFieldableEntityStorageInterface;
- use Drupal\Core\Field\BaseFieldDefinition;
- use Drupal\Core\Render\Element;
- use Drupal\language\Entity\ContentLanguageSettings;
- use Drupal\node\Entity\NodeType;
- /**
- * @defgroup entity_crud Entity CRUD, editing, and view hooks
- * @{
- * Hooks used in various entity operations.
- *
- * Entity create, read, update, and delete (CRUD) operations are performed by
- * entity storage classes; see the
- * @link entity_api Entity API topic @endlink for more information. Most
- * entities use or extend the default classes:
- * \Drupal\Core\Entity\Sql\SqlContentEntityStorage for content entities, and
- * \Drupal\Core\Config\Entity\ConfigEntityStorage for configuration entities.
- * For these entities, there is a set of hooks that is invoked for each
- * CRUD operation, which module developers can implement to affect these
- * operations; these hooks are actually invoked from methods on
- * \Drupal\Core\Entity\EntityStorageBase.
- *
- * For content entities, viewing and rendering are handled by a view builder
- * class; see the @link entity_api Entity API topic @endlink for more
- * information. Most view builders extend or use the default class
- * \Drupal\Core\Entity\EntityViewBuilder.
- *
- * Entity editing (including adding new entities) is handled by entity form
- * classes; see the @link entity_api Entity API topic @endlink for more
- * information. Most entity editing forms extend base classes
- * \Drupal\Core\Entity\EntityForm or \Drupal\Core\Entity\ContentEntityForm.
- * Note that many other operations, such as confirming deletion of entities,
- * also use entity form classes.
- *
- * This topic lists all of the entity CRUD and view operations, and the hooks
- * and other operations that are invoked (in order) for each operation. Some
- * notes:
- * - Whenever an entity hook is invoked, there is both a type-specific entity
- * hook, and a generic entity hook. For instance, during a create operation on
- * a node, first hook_node_create() and then hook_entity_create() would be
- * invoked.
- * - The entity-type-specific hooks are represented in the list below as
- * hook_ENTITY_TYPE_... (hook_ENTITY_TYPE_create() in this example). To
- * implement one of these hooks for an entity whose machine name is "foo",
- * define a function called mymodule_foo_create(), for instance. Also note
- * that the entity or array of entities that are passed into a specific-type
- * hook are of the specific entity class, not the generic Entity class, so in
- * your implementation, you can make the $entity argument something like $node
- * and give it a specific type hint (which should normally be to the specific
- * interface, such as \Drupal\Node\NodeInterface for nodes).
- * - $storage in the code examples is assumed to be an entity storage
- * class. See the @link entity_api Entity API topic @endlink for
- * information on how to instantiate the correct storage class for an
- * entity type.
- * - $view_builder in the code examples is assumed to be an entity view builder
- * class. See the @link entity_api Entity API topic @endlink for
- * information on how to instantiate the correct view builder class for
- * an entity type.
- * - During many operations, static methods are called on the entity class,
- * which implements \Drupal\Entity\EntityInterface.
- *
- * @section entities_revisions_translations Entities, revisions and translations
- * A content entity can have multiple stored variants: based on its definition,
- * it can be revisionable, translatable, or both.
- *
- * A revisionable entity can keep track of the changes that affect its data. In
- * fact all previous revisions of the entity can be stored and made available as
- * "historical" information. The "default" revision is the canonical variant of
- * the entity, the one that is loaded when no specific revision is requested.
- * Only changes to the default revision may be performed without triggering the
- * creation of a new revision, in any other case revision data is not supposed
- * to change. Aside from historical revisions, there can be "pending" revisions,
- * that contain changes that did not make their way into the default revision.
- * Typically these revisions contain data that is waiting for some form of
- * approval, before being accepted as canonical.
- * @see \Drupal\Core\Entity\RevisionableInterface
- * @see \Drupal\Core\Entity\RevisionableStorageInterface
- *
- * A translatable entity can contain multiple translations of the same content.
- * Content entity data is stored via fields, and each field can have one version
- * for each enabled language. Some fields may be defined as untranslatable,
- * which means that their values are shared among all translations. The
- * "default" translation is the canonical variant of the entity, the one whose
- * content will be accessible in the entity field data. Other translations
- * can be instantiated from the default one. Every translation has an "active
- * language" that is used to determine which field translation values should be
- * handled. Typically the default translation's active language is the language
- * of the content that was originally entered and served as source for the other
- * translations.
- * @see \Drupal\Core\Entity\TranslatableInterface
- * @see \Drupal\Core\Entity\TranslatableStorageInterface
- *
- * An entity that is both revisionable and translatable has all the features
- * described above: every revision can contain one or more translations. The
- * canonical variant of the entity is the default translation of the default
- * revision. Any revision will be initially loaded as the default translation,
- * the other revision translations can be instantiated from this one. If a
- * translation has changes in a certain revision, the translation is considered
- * "affected" by that revision, and will be flagged as such via the
- * "revision_translation_affected" field. With the built-in UI, every time a new
- * revision is saved, the changes for the edited translations will be stored,
- * while all field values for the other translations will be copied as-is.
- * However, if multiple translations of the default revision are being
- * subsequently modified without creating a new revision when saving, they will
- * all be affected by the default revision. Additionally, all revision
- * translations will be affected when saving a revision containing changes for
- * untranslatable fields. On the other hand, pending revisions are not supposed
- * to contain multiple affected translations, even when they are being
- * manipulated via the API.
- * @see \Drupal\Core\Entity\TranslatableRevisionableInterface
- * @see \Drupal\Core\Entity\TranslatableRevisionableStorageInterface
- *
- * @section create Create operations
- * To create an entity:
- * @code
- * $entity = $storage->create();
- *
- * // Add code here to set properties on the entity.
- *
- * // Until you call save(), the entity is just in memory.
- * $entity->save();
- * @endcode
- * There is also a shortcut method on entity classes, which creates an entity
- * with an array of provided property values: \Drupal\Core\Entity::create().
- *
- * Hooks invoked during the create operation:
- * - hook_ENTITY_TYPE_create()
- * - hook_entity_create()
- * - When handling content entities, if a new translation is added to the entity
- * object:
- * - hook_ENTITY_TYPE_translation_create()
- * - hook_entity_translation_create()
- *
- * See @ref save below for the save portion of the operation.
- *
- * @section load Read/Load operations
- * To load (read) a single entity:
- * @code
- * $entity = $storage->load($id);
- * @endcode
- * To load multiple entities:
- * @code
- * $entities = $storage->loadMultiple($ids);
- * @endcode
- * Since load() calls loadMultiple(), these are really the same operation.
- * Here is the order of hooks and other operations that take place during
- * entity loading:
- * - Entity is loaded from storage.
- * - postLoad() is called on the entity class, passing in all of the loaded
- * entities.
- * - hook_entity_load()
- * - hook_ENTITY_TYPE_load()
- *
- * When an entity is loaded, normally the default entity revision is loaded.
- * It is also possible to load a different revision, for entities that support
- * revisions, with this code:
- * @code
- * $entity = $storage->loadRevision($revision_id);
- * @endcode
- * This involves the same hooks and operations as regular entity loading.
- *
- * The "latest revision" of an entity is the most recently created one,
- * regardless of it being default or pending. If the entity is translatable,
- * revision translations are not taken into account either. In other words, any
- * time a new revision is created, that becomes the latest revision for the
- * entity overall, regardless of the affected translations. To load the latest
- * revision of an entity:
- * @code
- * $revision_id = $storage->getLatestRevisionId($entity_id);
- * $entity = $storage->loadRevision($revision_id);
- * @endcode
- * As usual, if the entity is translatable, this code instantiates into $entity
- * the default translation of the revision, even if the latest revision contains
- * only changes to a different translation:
- * @code
- * $is_default = $entity->isDefaultTranslation(); // returns TRUE
- * @endcode
- *
- * The "latest translation-affected revision" is the most recently created one
- * that affects the specified translation. For example, when a new revision
- * introducing some changes to an English translation is saved, that becomes the
- * new "latest revision". However, if an existing Italian translation was not
- * affected by those changes, then the "latest translation-affected revision"
- * for Italian remains what it was. To load the Italian translation at its
- * latest translation-affected revision:
- * @code
- * $revision_id = $storage->getLatestTranslationAffectedRevisionId($entity_id, 'it');
- * $it_translation = $storage->loadRevision($revision_id)->getTranslation('it');
- * @endcode
- *
- * @section save Save operations
- * To update an existing entity, you will need to load it, change properties,
- * and then save; as described above, when creating a new entity, you will also
- * need to save it. Here is the order of hooks and other events that happen
- * during an entity save:
- * - preSave() is called on the entity object, and field objects.
- * - hook_ENTITY_TYPE_presave()
- * - hook_entity_presave()
- * - Entity is saved to storage.
- * - For updates on content entities, if there is a translation added that
- * was not previously present:
- * - hook_ENTITY_TYPE_translation_insert()
- * - hook_entity_translation_insert()
- * - For updates on content entities, if there was a translation removed:
- * - hook_ENTITY_TYPE_translation_delete()
- * - hook_entity_translation_delete()
- * - postSave() is called on the entity object.
- * - hook_ENTITY_TYPE_insert() (new) or hook_ENTITY_TYPE_update() (update)
- * - hook_entity_insert() (new) or hook_entity_update() (update)
- *
- * Some specific entity types invoke hooks during preSave() or postSave()
- * operations. Examples:
- * - Field configuration preSave(): hook_field_storage_config_update_forbid()
- * - Node postSave(): hook_node_access_records() and
- * hook_node_access_records_alter()
- * - Config entities that are acting as entity bundles in postSave():
- * hook_entity_bundle_create()
- * - Comment: hook_comment_publish() and hook_comment_unpublish() as
- * appropriate.
- *
- * Note that all translations available for the entity are stored during a save
- * operation. When saving a new revision, a copy of every translation is stored,
- * regardless of it being affected by the revision.
- *
- * @section edit Editing operations
- * When an entity's add/edit form is used to add or edit an entity, there
- * are several hooks that are invoked:
- * - hook_entity_prepare_form()
- * - hook_ENTITY_TYPE_prepare_form()
- * - hook_entity_form_display_alter() (for content entities only)
- *
- * @section delete Delete operations
- * To delete one or more entities, load them and then delete them:
- * @code
- * $entities = $storage->loadMultiple($ids);
- * $storage->delete($entities);
- * @endcode
- *
- * During the delete operation, the following hooks and other events happen:
- * - preDelete() is called on the entity class.
- * - hook_ENTITY_TYPE_predelete()
- * - hook_entity_predelete()
- * - Entity and field information is removed from storage.
- * - postDelete() is called on the entity class.
- * - hook_ENTITY_TYPE_delete()
- * - hook_entity_delete()
- *
- * Some specific entity types invoke hooks during the delete process. Examples:
- * - Entity bundle postDelete(): hook_entity_bundle_delete()
- *
- * Individual revisions of an entity can also be deleted:
- * @code
- * $storage->deleteRevision($revision_id);
- * @endcode
- * This operation invokes the following operations and hooks:
- * - Revision is loaded (see @ref load above).
- * - Revision and field information is removed from the database.
- * - hook_ENTITY_TYPE_revision_delete()
- * - hook_entity_revision_delete()
- *
- * @section view View/render operations
- * To make a render array for a loaded entity:
- * @code
- * // You can omit the language ID if the default language is being used.
- * $build = $view_builder->view($entity, 'view_mode_name', $language->getId());
- * @endcode
- * You can also use the viewMultiple() method to view multiple entities.
- *
- * Hooks invoked during the operation of building a render array:
- * - hook_entity_view_mode_alter()
- * - hook_ENTITY_TYPE_build_defaults_alter()
- * - hook_entity_build_defaults_alter()
- *
- * View builders for some types override these hooks, notably:
- * - The Tour view builder does not invoke any hooks.
- * - The Block view builder invokes hook_block_view_alter() and
- * hook_block_view_BASE_BLOCK_ID_alter(). Note that in other view builders,
- * the view alter hooks are run later in the process.
- *
- * During the rendering operation, the default entity viewer runs the following
- * hooks and operations in the pre-render step:
- * - hook_entity_view_display_alter()
- * - hook_entity_prepare_view()
- * - Entity fields are loaded, and render arrays are built for them using
- * their formatters.
- * - hook_entity_display_build_alter()
- * - hook_ENTITY_TYPE_view()
- * - hook_entity_view()
- * - hook_ENTITY_TYPE_view_alter()
- * - hook_entity_view_alter()
- *
- * Some specific builders have specific hooks:
- * - The Node view builder invokes hook_node_links_alter().
- * - The Comment view builder invokes hook_comment_links_alter().
- *
- * After this point in rendering, the theme system takes over. See the
- * @link theme_render Theme system and render API topic @endlink for more
- * information.
- *
- * @section misc Other entity hooks
- * Some types of entities invoke hooks for specific operations:
- * - Searching nodes:
- * - hook_ranking()
- * - Query is executed to find matching nodes
- * - Resulting node is loaded
- * - Node render array is built
- * - comment_node_update_index() is called (this adds "N comments" text)
- * - hook_node_search_result()
- * - Search indexing nodes:
- * - Node is loaded
- * - Node render array is built
- * - hook_node_update_index()
- * @}
- */
- /**
- * @defgroup entity_api Entity API
- * @{
- * Describes how to define and manipulate content and configuration entities.
- *
- * Entities, in Drupal, are objects that are used for persistent storage of
- * content and configuration information. See the
- * @link info_types Information types topic @endlink for an overview of the
- * different types of information, and the
- * @link config_api Configuration API topic @endlink for more about the
- * configuration API.
- *
- * Each entity is an instance of a particular "entity type". Some content entity
- * types have sub-types, which are known as "bundles", while for other entity
- * types, there is only a single bundle. For example, the Node content entity
- * type, which is used for the main content pages in Drupal, has bundles that
- * are known as "content types", while the User content type, which is used for
- * user accounts, has only one bundle.
- *
- * The sections below have more information about entities and the Entity API;
- * for more detailed information, see
- * https://www.drupal.org/developing/api/entity.
- *
- * @section define Defining an entity type
- * Entity types are defined by modules, using Drupal's Plugin API (see the
- * @link plugin_api Plugin API topic @endlink for more information about plugins
- * in general). Here are the steps to follow to define a new entity type:
- * - Choose a unique machine name, or ID, for your entity type. This normally
- * starts with (or is the same as) your module's machine name. It should be
- * as short as possible, and may not exceed 32 characters.
- * - Define an interface for your entity's get/set methods, usually extending
- * either \Drupal\Core\Config\Entity\ConfigEntityInterface or
- * \Drupal\Core\Entity\ContentEntityInterface.
- * - Define a class for your entity, implementing your interface and extending
- * either \Drupal\Core\Config\Entity\ConfigEntityBase or
- * \Drupal\Core\Entity\ContentEntityBase, with annotation for
- * \@ConfigEntityType or \@ContentEntityType in its documentation block.
- * If you are defining a content entity type, it is recommended to extend the
- * \Drupal\Core\Entity\EditorialContentEntityBase base class in order to get
- * out-of-the-box support for Entity API's revisioning and publishing
- * features, which will allow your entity type to be used with Drupal's
- * editorial workflow provided by the Content Moderation module.
- * - In the annotation, the 'id' property gives the entity type ID, and the
- * 'label' property gives the human-readable name of the entity type. If you
- * are defining a content entity type that uses bundles, the 'bundle_label'
- * property gives the human-readable name to use for a bundle of this entity
- * type (for example, "Content type" for the Node entity).
- * - The annotation will refer to several handler classes, which you will also
- * need to define:
- * - list_builder: Define a class that extends
- * \Drupal\Core\Config\Entity\ConfigEntityListBuilder (for configuration
- * entities) or \Drupal\Core\Entity\EntityListBuilder (for content
- * entities), to provide an administrative overview for your entities.
- * - add and edit forms, or default form: Define a class (or two) that
- * extend(s) \Drupal\Core\Entity\EntityForm to provide add and edit forms
- * for your entities. For content entities, base class
- * \Drupal\Core\Entity\ContentEntityForm is a better starting point.
- * - delete form: Define a class that extends
- * \Drupal\Core\Entity\EntityConfirmFormBase to provide a delete
- * confirmation form for your entities.
- * - view_builder: For content entities and config entities that need to be
- * viewed, define a class that implements
- * \Drupal\Core\Entity\EntityViewBuilderInterface (usually extending
- * \Drupal\Core\Entity\EntityViewBuilder), to display a single entity.
- * - translation: For translatable content entities (if the 'translatable'
- * annotation property has value TRUE), define a class that extends
- * \Drupal\content_translation\ContentTranslationHandler, to translate
- * the content. Configuration translation is handled automatically by the
- * Configuration Translation module, without the need of a handler class.
- * - access: If your configuration entity has complex permissions, you might
- * need an access control handling, implementing
- * \Drupal\Core\Entity\EntityAccessControlHandlerInterface, but most
- * entities can just use the 'admin_permission' annotation property
- * instead. Note that if you are creating your own access control handler,
- * you should override the checkAccess() and checkCreateAccess() methods,
- * not access().
- * - storage: A class implementing
- * \Drupal\Core\Entity\EntityStorageInterface. If not specified, content
- * entities will use \Drupal\Core\Entity\Sql\SqlContentEntityStorage, and
- * config entities will use \Drupal\Core\Config\Entity\ConfigEntityStorage.
- * You can extend one of these classes to provide custom behavior.
- * - views_data: A class implementing \Drupal\views\EntityViewsDataInterface
- * to provide views data for the entity type. You can autogenerate most of
- * the views data by extending \Drupal\views\EntityViewsData.
- * - For content entities, the annotation will refer to a number of database
- * tables and their fields. These annotation properties, such as 'base_table',
- * 'data_table', 'entity_keys', etc., are documented on
- * \Drupal\Core\Entity\EntityType.
- * - For content entities that are displayed on their own pages, the annotation
- * will refer to a 'uri_callback' function, which takes an object of the
- * entity interface you have defined as its parameter, and returns routing
- * information for the entity page; see node_uri() for an example. You will
- * also need to add a corresponding route to your module's routing.yml file;
- * see the entity.node.canonical route in node.routing.yml for an example, and see
- * @ref sec_routes below for some notes.
- * - Optionally, instead of defining routes, routes can be auto generated by
- * providing a route handler. See @ref sec_routes. Otherwise, define routes
- * and links for the various URLs associated with the entity.
- * These go into the 'links' annotation, with the link type as the key, and
- * the path of this link template as the value. The corresponding route
- * requires the following route name:
- * "entity.$entity_type_id.$link_template_type". See @ref sec_routes below for
- * some routing notes. Typical link types are:
- * - canonical: Default link, either to view (if entities are viewed on their
- * own pages) or edit the entity.
- * - delete-form: Confirmation form to delete the entity.
- * - edit-form: Editing form.
- * - Other link types specific to your entity type can also be defined.
- * - If your content entity is fieldable, provide the 'field_ui_base_route'
- * annotation property, giving the name of the route that the Manage Fields,
- * Manage Display, and Manage Form Display pages from the Field UI module
- * will be attached to. This is usually the bundle settings edit page, or an
- * entity type settings page if there are no bundles.
- * - If your content entity has bundles, you will also need to define a second
- * plugin to handle the bundles. This plugin is itself a configuration entity
- * type, so follow the steps here to define it. The machine name ('id'
- * annotation property) of this configuration entity class goes into the
- * 'bundle_entity_type' annotation property on the entity type class. For
- * example, for the Node entity, the bundle class is
- * \Drupal\node\Entity\NodeType, whose machine name is 'node_type'. This is
- * the annotation property 'bundle_entity_type' on the
- * \Drupal\node\Entity\Node class. Also, the
- * bundle config entity type annotation must have a 'bundle_of' property,
- * giving the machine name of the entity type it is acting as a bundle for.
- * These machine names are considered permanent, they may not be renamed.
- * - Additional annotation properties can be seen on entity class examples such
- * as \Drupal\node\Entity\Node (content) and \Drupal\user\Entity\Role
- * (configuration). These annotation properties are documented on
- * \Drupal\Core\Entity\EntityType.
- *
- * @section sec_routes Entity routes
- * Entity routes can be defined in *.routing.yml files, like any other route:
- * see the @link routing Routing API @endlink topic for more information.
- * Another option for entity routes is to use a route provider class, and
- * reference it in the annotations on the entity class: see the end of this
- * section for an example.
- *
- * It's possible to use both a YAML file and a provider class for entity
- * routes, at the same time. Avoid duplicating route names between the two:
- * if a duplicate route name is found in both locations, the one in the YAML
- * file takes precedence; regardless, such duplication can be confusing.
- *
- * Here's an example YAML route specification, for the block configure form:
- * @code
- * entity.block.edit_form:
- * path: '/admin/structure/block/manage/{block}'
- * defaults:
- * _entity_form: 'block.default'
- * _title: 'Configure block'
- * requirements:
- * _entity_access: 'block.update'
- * @endcode
- * Some notes on this example:
- * - path: The {block} in the path is a placeholder, which (for an entity) must
- * always take the form of {machine_name_of_entity_type}. In the URL, the
- * placeholder value will be the ID of an entity item. When the route is used,
- * the entity system will load the corresponding entity item and pass it in as
- * an object to the controller for the route.
- * - defaults: For entity form routes, use _entity_form rather than the generic
- * _controller or _form. The value is composed of the entity type machine name
- * and a form handler type from the entity annotation (see @ref define above
- * more more on handlers and annotation). So, in this example, block.default
- * refers to the 'default' form handler on the block entity type, whose
- * annotation contains:
- * @code
- * handlers = {
- * "form" = {
- * "default" = "Drupal\block\BlockForm",
- * @endcode
- * If instead of YAML you want to use a route provider class:
- * - \Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider provides canonical,
- * edit-form, and delete-form routes.
- * - \Drupal\Core\Entity\Routing\AdminHtmlRouteProvider provides the same
- * routes, set up to use the administrative theme for edit and delete pages.
- * - You can also create your own class, extending one of these two classes if
- * you only want to modify their behaviour slightly.
- *
- * To register any route provider class, add lines like the following to your
- * entity class annotation:
- * @code
- * handlers = {
- * "route_provider" = {
- * "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- * @endcode
- *
- * @section bundle Defining a content entity bundle
- * For entity types that use bundles, such as Node (bundles are content types)
- * and Taxonomy (bundles are vocabularies), modules and install profiles can
- * define bundles by supplying default configuration in their config/install
- * directories. (See the @link config_api Configuration API topic @endlink for
- * general information about configuration.)
- *
- * There are several good examples of this in Drupal Core:
- * - The Forum module defines a content type in node.type.forum.yml and a
- * vocabulary in taxonomy.vocabulary.forums.yml
- * - The Book module defines a content type in node.type.book.yml
- * - The Standard install profile defines Page and Article content types in
- * node.type.page.yml and node.type.article.yml, a Tags vocabulary in
- * taxonomy.vocabulary.tags.yml, and a Node comment type in
- * comment.type.comment.yml. This profile's configuration is especially
- * instructive, because it also adds several fields to the Article type, and
- * it sets up view and form display modes for the node types.
- *
- * @section load_query Loading, querying, and rendering entities
- * To load entities, use the entity storage manager, which is an object
- * implementing \Drupal\Core\Entity\EntityStorageInterface that you can
- * retrieve with:
- * @code
- * $storage = \Drupal::entityManager()->getStorage('your_entity_type');
- * // Or if you have a $container variable:
- * $storage = $container->get('entity.manager')->getStorage('your_entity_type');
- * @endcode
- * Here, 'your_entity_type' is the machine name of your entity type ('id'
- * annotation property on the entity class), and note that you should use
- * dependency injection to retrieve this object if possible. See the
- * @link container Services and Dependency Injection topic @endlink for more
- * about how to properly retrieve services.
- *
- * To query to find entities to load, use an entity query, which is a object
- * implementing \Drupal\Core\Entity\Query\QueryInterface that you can retrieve
- * with:
- * @code
- * // Simple query:
- * $query = \Drupal::entityQuery('your_entity_type');
- * // Or, if you have a $container variable:
- * $storage = $container->get('entity_type.manager')->getStorage('your_entity_type');
- * $query = $storage->getQuery();
- * @endcode
- * If you need aggregation, there is an aggregate query available, which
- * implements \Drupal\Core\Entity\Query\QueryAggregateInterface:
- * @code
- * $query \Drupal::entityQueryAggregate('your_entity_type');
- * // Or:
- * $query = $storage->getAggregateQuery('your_entity_type');
- * @endcode
- *
- * In either case, you can then add conditions to your query, using methods
- * like condition(), exists(), etc. on $query; add sorting, pager, and range
- * if needed, and execute the query to return a list of entity IDs that match
- * the query.
- *
- * Here is an example, using the core File entity:
- * @code
- * $fids = Drupal::entityQuery('file')
- * ->condition('status', FILE_STATUS_PERMANENT, '<>')
- * ->condition('changed', REQUEST_TIME - $age, '<')
- * ->range(0, 100)
- * ->execute();
- * $files = $storage->loadMultiple($fids);
- * @endcode
- *
- * The normal way of viewing entities is by using a route, as described in the
- * sections above. If for some reason you need to render an entity in code in a
- * particular view mode, you can use an entity view builder, which is an object
- * implementing \Drupal\Core\Entity\EntityViewBuilderInterface that you can
- * retrieve with:
- * @code
- * $view_builder = \Drupal::entityManager()->getViewBuilder('your_entity_type');
- * // Or if you have a $container variable:
- * $view_builder = $container->get('entity.manager')->getViewBuilder('your_entity_type');
- * @endcode
- * Then, to build and render the entity:
- * @code
- * // You can omit the language ID, by default the current content language will
- * // be used. If no translation is available for the current language, fallback
- * // rules will be used.
- * $build = $view_builder->view($entity, 'view_mode_name', $language->getId());
- * // $build is a render array.
- * $rendered = drupal_render($build);
- * @endcode
- *
- * @section sec_access Access checking on entities
- * Entity types define their access permission scheme in their annotation.
- * Access permissions can be quite complex, so you should not assume any
- * particular permission scheme. Instead, once you have an entity object
- * loaded, you can check for permission for a particular operation (such as
- * 'view') at the entity or field level by calling:
- * @code
- * $entity->access($operation);
- * $entity->nameOfField->access($operation);
- * @endcode
- * The interface related to access checking in entities and fields is
- * \Drupal\Core\Access\AccessibleInterface.
- *
- * The default entity access control handler invokes two hooks while checking
- * access on a single entity: hook_entity_access() is invoked first, and
- * then hook_ENTITY_TYPE_access() (where ENTITY_TYPE is the machine name
- * of the entity type). If no module returns a TRUE or FALSE value from
- * either of these hooks, then the entity's default access checking takes
- * place. For create operations (creating a new entity), the hooks that
- * are invoked are hook_entity_create_access() and
- * hook_ENTITY_TYPE_create_access() instead.
- *
- * The Node entity type has a complex system for determining access, which
- * developers can interact with. This is described in the
- * @link node_access Node access topic. @endlink
- *
- * @see i18n
- * @see entity_crud
- * @see \Drupal\Core\Entity\EntityManagerInterface::getTranslationFromContext()
- * @}
- */
- /**
- * @addtogroup hooks
- * @{
- */
- /**
- * Control entity operation access.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity to check access to.
- * @param string $operation
- * The operation that is to be performed on $entity.
- * @param \Drupal\Core\Session\AccountInterface $account
- * The account trying to access the entity.
- *
- * @return \Drupal\Core\Access\AccessResultInterface
- * The access result. The final result is calculated by using
- * \Drupal\Core\Access\AccessResultInterface::orIf() on the result of every
- * hook_entity_access() and hook_ENTITY_TYPE_access() implementation, and the
- * result of the entity-specific checkAccess() method in the entity access
- * control handler. Be careful when writing generalized access checks shared
- * between routing and entity checks: routing uses the andIf() operator. So
- * returning an isNeutral() does not determine entity access at all but it
- * always ends up denying access while routing.
- *
- * @see \Drupal\Core\Entity\EntityAccessControlHandler
- * @see hook_entity_create_access()
- * @see hook_ENTITY_TYPE_access()
- *
- * @ingroup entity_api
- */
- function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account) {
- // No opinion.
- return AccessResult::neutral();
- }
- /**
- * Control entity operation access for a specific entity type.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity to check access to.
- * @param string $operation
- * The operation that is to be performed on $entity.
- * @param \Drupal\Core\Session\AccountInterface $account
- * The account trying to access the entity.
- *
- * @return \Drupal\Core\Access\AccessResultInterface
- * The access result. hook_entity_access() has detailed documentation.
- *
- * @see \Drupal\Core\Entity\EntityAccessControlHandler
- * @see hook_ENTITY_TYPE_create_access()
- * @see hook_entity_access()
- *
- * @ingroup entity_api
- */
- function hook_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account) {
- // No opinion.
- return AccessResult::neutral();
- }
- /**
- * Control entity create access.
- *
- * @param \Drupal\Core\Session\AccountInterface $account
- * The account trying to access the entity.
- * @param array $context
- * An associative array of additional context values. By default it contains
- * language and the entity type ID:
- * - entity_type_id - the entity type ID.
- * - langcode - the current language code.
- * @param string $entity_bundle
- * The entity bundle name.
- *
- * @return \Drupal\Core\Access\AccessResultInterface
- * The access result.
- *
- * @see \Drupal\Core\Entity\EntityAccessControlHandler
- * @see hook_entity_access()
- * @see hook_ENTITY_TYPE_create_access()
- *
- * @ingroup entity_api
- */
- function hook_entity_create_access(\Drupal\Core\Session\AccountInterface $account, array $context, $entity_bundle) {
- // No opinion.
- return AccessResult::neutral();
- }
- /**
- * Control entity create access for a specific entity type.
- *
- * @param \Drupal\Core\Session\AccountInterface $account
- * The account trying to access the entity.
- * @param array $context
- * An associative array of additional context values. By default it contains
- * language:
- * - langcode - the current language code.
- * @param string $entity_bundle
- * The entity bundle name.
- *
- * @return \Drupal\Core\Access\AccessResultInterface
- * The access result.
- *
- * @see \Drupal\Core\Entity\EntityAccessControlHandler
- * @see hook_ENTITY_TYPE_access()
- * @see hook_entity_create_access()
- *
- * @ingroup entity_api
- */
- function hook_ENTITY_TYPE_create_access(\Drupal\Core\Session\AccountInterface $account, array $context, $entity_bundle) {
- // No opinion.
- return AccessResult::neutral();
- }
- /**
- * Add to entity type definitions.
- *
- * Modules may implement this hook to add information to defined entity types,
- * as defined in \Drupal\Core\Entity\EntityTypeInterface.
- *
- * To alter existing information or to add information dynamically, use
- * hook_entity_type_alter().
- *
- * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types
- * An associative array of all entity type definitions, keyed by the entity
- * type name. Passed by reference.
- *
- * @see \Drupal\Core\Entity\Entity
- * @see \Drupal\Core\Entity\EntityTypeInterface
- * @see hook_entity_type_alter()
- */
- function hook_entity_type_build(array &$entity_types) {
- /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
- // Add a form for a custom node form without overriding the default
- // node form. To override the default node form, use hook_entity_type_alter().
- $entity_types['node']->setFormClass('mymodule_foo', 'Drupal\mymodule\NodeFooForm');
- }
- /**
- * Alter the entity type definitions.
- *
- * Modules may implement this hook to alter the information that defines an
- * entity type. All properties that are available in
- * \Drupal\Core\Entity\Annotation\EntityType and all the ones additionally
- * provided by modules can be altered here.
- *
- * Do not use this hook to add information to entity types, unless one of the
- * following is true:
- * - You are filling in default values.
- * - You need to dynamically add information only in certain circumstances.
- * - Your hook needs to run after hook_entity_type_build() implementations.
- * Use hook_entity_type_build() instead in all other cases.
- *
- * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types
- * An associative array of all entity type definitions, keyed by the entity
- * type name. Passed by reference.
- *
- * @see \Drupal\Core\Entity\Entity
- * @see \Drupal\Core\Entity\EntityTypeInterface
- */
- function hook_entity_type_alter(array &$entity_types) {
- /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
- // Set the controller class for nodes to an alternate implementation of the
- // Drupal\Core\Entity\EntityStorageInterface interface.
- $entity_types['node']->setStorageClass('Drupal\mymodule\MyCustomNodeStorage');
- }
- /**
- * Alter the view modes for entity types.
- *
- * @param array $view_modes
- * An array of view modes, keyed first by entity type, then by view mode name.
- *
- * @see \Drupal\Core\Entity\EntityManagerInterface::getAllViewModes()
- * @see \Drupal\Core\Entity\EntityManagerInterface::getViewModes()
- */
- function hook_entity_view_mode_info_alter(&$view_modes) {
- $view_modes['user']['full']['status'] = TRUE;
- }
- /**
- * Describe the bundles for entity types.
- *
- * @return array
- * An associative array of all entity bundles, keyed by the entity
- * type name, and then the bundle name, with the following keys:
- * - label: The human-readable name of the bundle.
- * - uri_callback: The same as the 'uri_callback' key defined for the entity
- * type in the EntityManager, but for the bundle only. When determining
- * the URI of an entity, if a 'uri_callback' is defined for both the
- * entity type and the bundle, the one for the bundle is used.
- * - translatable: (optional) A boolean value specifying whether this bundle
- * has translation support enabled. Defaults to FALSE.
- *
- * @see \Drupal\Core\Entity\EntityTypeBundleInfo::getBundleInfo()
- * @see hook_entity_bundle_info_alter()
- */
- function hook_entity_bundle_info() {
- $bundles['user']['user']['label'] = t('User');
- return $bundles;
- }
- /**
- * Alter the bundles for entity types.
- *
- * @param array $bundles
- * An array of bundles, keyed first by entity type, then by bundle name.
- *
- * @see Drupal\Core\Entity\EntityTypeBundleInfo::getBundleInfo()
- * @see hook_entity_bundle_info()
- */
- function hook_entity_bundle_info_alter(&$bundles) {
- $bundles['user']['user']['label'] = t('Full account');
- }
- /**
- * Act on entity_bundle_create().
- *
- * This hook is invoked after the operation has been performed.
- *
- * @param string $entity_type_id
- * The type of $entity; e.g. 'node' or 'user'.
- * @param string $bundle
- * The name of the bundle.
- *
- * @see entity_crud
- */
- function hook_entity_bundle_create($entity_type_id, $bundle) {
- // When a new bundle is created, the menu needs to be rebuilt to add the
- // Field UI menu item tabs.
- \Drupal::service('router.builder')->setRebuildNeeded();
- }
- /**
- * Act on entity_bundle_delete().
- *
- * This hook is invoked after the operation has been performed.
- *
- * @param string $entity_type_id
- * The type of entity; for example, 'node' or 'user'.
- * @param string $bundle
- * The bundle that was just deleted.
- *
- * @ingroup entity_crud
- */
- function hook_entity_bundle_delete($entity_type_id, $bundle) {
- // Remove the settings associated with the bundle in my_module.settings.
- $config = \Drupal::config('my_module.settings');
- $bundle_settings = $config->get('bundle_settings');
- if (isset($bundle_settings[$entity_type_id][$bundle])) {
- unset($bundle_settings[$entity_type_id][$bundle]);
- $config->set('bundle_settings', $bundle_settings);
- }
- }
- /**
- * Acts when creating a new entity.
- *
- * This hook runs after a new entity object has just been instantiated.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object.
- *
- * @ingroup entity_crud
- * @see hook_ENTITY_TYPE_create()
- */
- function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) {
- \Drupal::logger('example')->info('Entity created: @label', ['@label' => $entity->label()]);
- }
- /**
- * Acts when creating a new entity of a specific type.
- *
- * This hook runs after a new entity object has just been instantiated.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object.
- *
- * @ingroup entity_crud
- * @see hook_entity_create()
- */
- function hook_ENTITY_TYPE_create(\Drupal\Core\Entity\EntityInterface $entity) {
- \Drupal::logger('example')->info('ENTITY_TYPE created: @label', ['@label' => $entity->label()]);
- }
- /**
- * Act on entities when loaded.
- *
- * This is a generic load hook called for all entity types loaded via the
- * entity API.
- *
- * hook_entity_storage_load() should be used to load additional data for
- * content entities.
- *
- * @param \Drupal\Core\Entity\EntityInterface[] $entities
- * The entities keyed by entity ID.
- * @param string $entity_type_id
- * The type of entities being loaded (i.e. node, user, comment).
- *
- * @ingroup entity_crud
- * @see hook_ENTITY_TYPE_load()
- */
- function hook_entity_load(array $entities, $entity_type_id) {
- foreach ($entities as $entity) {
- $entity->foo = mymodule_add_something($entity);
- }
- }
- /**
- * Act on entities of a specific type when loaded.
- *
- * @param array $entities
- * The entities keyed by entity ID.
- *
- * @ingroup entity_crud
- * @see hook_entity_load()
- */
- function hook_ENTITY_TYPE_load($entities) {
- foreach ($entities as $entity) {
- $entity->foo = mymodule_add_something($entity);
- }
- }
- /**
- * Act on content entities when loaded from the storage.
- *
- * The results of this hook will be cached.
- *
- * @param \Drupal\Core\Entity\EntityInterface[] $entities
- * The entities keyed by entity ID.
- * @param string $entity_type
- * The type of entities being loaded (i.e. node, user, comment).
- *
- * @see hook_entity_load()
- */
- function hook_entity_storage_load(array $entities, $entity_type) {
- foreach ($entities as $entity) {
- $entity->foo = mymodule_add_something_uncached($entity);
- }
- }
- /**
- * Act on content entities of a given type when loaded from the storage.
- *
- * The results of this hook will be cached if the entity type supports it.
- *
- * @param \Drupal\Core\Entity\EntityInterface[] $entities
- * The entities keyed by entity ID.
- *
- * @see hook_entity_storage_load()
- */
- function hook_ENTITY_TYPE_storage_load(array $entities) {
- foreach ($entities as $entity) {
- $entity->foo = mymodule_add_something_uncached($entity);
- }
- }
- /**
- * Act on an entity before it is created or updated.
- *
- * You can get the original entity object from $entity->original when it is an
- * update of the entity.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object.
- *
- * @ingroup entity_crud
- * @see hook_ENTITY_TYPE_presave()
- */
- function hook_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
- if ($entity instanceof ContentEntityInterface && $entity->isTranslatable()) {
- $route_match = \Drupal::routeMatch();
- \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->getId(), $route_match->getParameter('source_langcode'));
- }
- }
- /**
- * Act on a specific type of entity before it is created or updated.
- *
- * You can get the original entity object from $entity->original when it is an
- * update of the entity.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object.
- *
- * @ingroup entity_crud
- * @see hook_entity_presave()
- */
- function hook_ENTITY_TYPE_presave(Drupal\Core\Entity\EntityInterface $entity) {
- if ($entity->isTranslatable()) {
- $route_match = \Drupal::routeMatch();
- \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->getId(), $route_match->getParameter('source_langcode'));
- }
- }
- /**
- * Respond to creation of a new entity.
- *
- * This hook runs once the entity has been stored. Note that hook
- * implementations may not alter the stored entity data.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object.
- *
- * @ingroup entity_crud
- * @see hook_ENTITY_TYPE_insert()
- */
- function hook_entity_insert(Drupal\Core\Entity\EntityInterface $entity) {
- // Insert the new entity into a fictional table of all entities.
- db_insert('example_entity')
- ->fields([
- 'type' => $entity->getEntityTypeId(),
- 'id' => $entity->id(),
- 'created' => REQUEST_TIME,
- 'updated' => REQUEST_TIME,
- ])
- ->execute();
- }
- /**
- * Respond to creation of a new entity of a particular type.
- *
- * This hook runs once the entity has been stored. Note that hook
- * implementations may not alter the stored entity data.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object.
- *
- * @ingroup entity_crud
- * @see hook_entity_insert()
- */
- function hook_ENTITY_TYPE_insert(Drupal\Core\Entity\EntityInterface $entity) {
- // Insert the new entity into a fictional table of this type of entity.
- db_insert('example_entity')
- ->fields([
- 'id' => $entity->id(),
- 'created' => REQUEST_TIME,
- 'updated' => REQUEST_TIME,
- ])
- ->execute();
- }
- /**
- * Respond to updates to an entity.
- *
- * This hook runs once the entity storage has been updated. Note that hook
- * implementations may not alter the stored entity data. Get the original entity
- * object from $entity->original.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object.
- *
- * @ingroup entity_crud
- * @see hook_ENTITY_TYPE_update()
- */
- function hook_entity_update(Drupal\Core\Entity\EntityInterface $entity) {
- // Update the entity's entry in a fictional table of all entities.
- db_update('example_entity')
- ->fields([
- 'updated' => REQUEST_TIME,
- ])
- ->condition('type', $entity->getEntityTypeId())
- ->condition('id', $entity->id())
- ->execute();
- }
- /**
- * Respond to updates to an entity of a particular type.
- *
- * This hook runs once the entity storage has been updated. Note that hook
- * implementations may not alter the stored entity data. Get the original entity
- * object from $entity->original.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object.
- *
- * @ingroup entity_crud
- * @see hook_entity_update()
- */
- function hook_ENTITY_TYPE_update(Drupal\Core\Entity\EntityInterface $entity) {
- // Update the entity's entry in a fictional table of this type of entity.
- db_update('example_entity')
- ->fields([
- 'updated' => REQUEST_TIME,
- ])
- ->condition('id', $entity->id())
- ->execute();
- }
- /**
- * Acts when creating a new entity translation.
- *
- * This hook runs after a new entity translation object has just been
- * instantiated.
- *
- * @param \Drupal\Core\Entity\EntityInterface $translation
- * The entity object.
- *
- * @ingroup entity_crud
- * @see hook_ENTITY_TYPE_translation_create()
- */
- function hook_entity_translation_create(\Drupal\Core\Entity\EntityInterface $translation) {
- \Drupal::logger('example')->info('Entity translation created: @label', ['@label' => $translation->label()]);
- }
- /**
- * Acts when creating a new entity translation of a specific type.
- *
- * This hook runs after a new entity translation object has just been
- * instantiated.
- *
- * @param \Drupal\Core\Entity\EntityInterface $translation
- * The entity object.
- *
- * @ingroup entity_crud
- * @see hook_entity_translation_create()
- */
- function hook_ENTITY_TYPE_translation_create(\Drupal\Core\Entity\EntityInterface $translation) {
- \Drupal::logger('example')->info('ENTITY_TYPE translation created: @label', ['@label' => $translation->label()]);
- }
- /**
- * Respond to creation of a new entity translation.
- *
- * This hook runs once the entity translation has been stored. Note that hook
- * implementations may not alter the stored entity translation data.
- *
- * @param \Drupal\Core\Entity\EntityInterface $translation
- * The entity object of the translation just stored.
- *
- * @ingroup entity_crud
- * @see hook_ENTITY_TYPE_translation_insert()
- */
- function hook_entity_translation_insert(\Drupal\Core\Entity\EntityInterface $translation) {
- $variables = [
- '@language' => $translation->language()->getName(),
- '@label' => $translation->getUntranslated()->label(),
- ];
- \Drupal::logger('example')->notice('The @language translation of @label has just been stored.', $variables);
- }
- /**
- * Respond to creation of a new entity translation of a particular type.
- *
- * This hook runs once the entity translation has been stored. Note that hook
- * implementations may not alter the stored entity translation data.
- *
- * @param \Drupal\Core\Entity\EntityInterface $translation
- * The entity object of the translation just stored.
- *
- * @ingroup entity_crud
- * @see hook_entity_translation_insert()
- */
- function hook_ENTITY_TYPE_translation_insert(\Drupal\Core\Entity\EntityInterface $translation) {
- $variables = [
- '@language' => $translation->language()->getName(),
- '@label' => $translation->getUntranslated()->label(),
- ];
- \Drupal::logger('example')->notice('The @language translation of @label has just been stored.', $variables);
- }
- /**
- * Respond to entity translation deletion.
- *
- * This hook runs once the entity translation has been deleted from storage.
- *
- * @param \Drupal\Core\Entity\EntityInterface $translation
- * The original entity object.
- *
- * @ingroup entity_crud
- * @see hook_ENTITY_TYPE_translation_delete()
- */
- function hook_entity_translation_delete(\Drupal\Core\Entity\EntityInterface $translation) {
- $variables = [
- '@language' => $translation->language()->getName(),
- '@label' => $translation->label(),
- ];
- \Drupal::logger('example')->notice('The @language translation of @label has just been deleted.', $variables);
- }
- /**
- * Respond to entity translation deletion of a particular type.
- *
- * This hook runs once the entity translation has been deleted from storage.
- *
- * @param \Drupal\Core\Entity\EntityInterface $translation
- * The original entity object.
- *
- * @ingroup entity_crud
- * @see hook_entity_translation_delete()
- */
- function hook_ENTITY_TYPE_translation_delete(\Drupal\Core\Entity\EntityInterface $translation) {
- $variables = [
- '@language' => $translation->language()->getName(),
- '@label' => $translation->label(),
- ];
- \Drupal::logger('example')->notice('The @language translation of @label has just been deleted.', $variables);
- }
- /**
- * Act before entity deletion.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object for the entity that is about to be deleted.
- *
- * @ingroup entity_crud
- * @see hook_ENTITY_TYPE_predelete()
- */
- function hook_entity_predelete(Drupal\Core\Entity\EntityInterface $entity) {
- // Count references to this entity in a custom table before they are removed
- // upon entity deletion.
- $id = $entity->id();
- $type = $entity->getEntityTypeId();
- $count = db_select('example_entity_data')
- ->condition('type', $type)
- ->condition('id', $id)
- ->countQuery()
- ->execute()
- ->fetchField();
- // Log the count in a table that records this statistic for deleted entities.
- db_merge('example_deleted_entity_statistics')
- ->key(['type' => $type, 'id' => $id])
- ->fields(['count' => $count])
- ->execute();
- }
- /**
- * Act before entity deletion of a particular entity type.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object for the entity that is about to be deleted.
- *
- * @ingroup entity_crud
- * @see hook_entity_predelete()
- */
- function hook_ENTITY_TYPE_predelete(Drupal\Core\Entity\EntityInterface $entity) {
- // Count references to this entity in a custom table before they are removed
- // upon entity deletion.
- $id = $entity->id();
- $type = $entity->getEntityTypeId();
- $count = db_select('example_entity_data')
- ->condition('type', $type)
- ->condition('id', $id)
- ->countQuery()
- ->execute()
- ->fetchField();
- // Log the count in a table that records this statistic for deleted entities.
- db_merge('example_deleted_entity_statistics')
- ->key(['type' => $type, 'id' => $id])
- ->fields(['count' => $count])
- ->execute();
- }
- /**
- * Respond to entity deletion.
- *
- * This hook runs once the entity has been deleted from the storage.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object for the entity that has been deleted.
- *
- * @ingroup entity_crud
- * @see hook_ENTITY_TYPE_delete()
- */
- function hook_entity_delete(Drupal\Core\Entity\EntityInterface $entity) {
- // Delete the entity's entry from a fictional table of all entities.
- db_delete('example_entity')
- ->condition('type', $entity->getEntityTypeId())
- ->condition('id', $entity->id())
- ->execute();
- }
- /**
- * Respond to entity deletion of a particular type.
- *
- * This hook runs once the entity has been deleted from the storage.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object for the entity that has been deleted.
- *
- * @ingroup entity_crud
- * @see hook_entity_delete()
- */
- function hook_ENTITY_TYPE_delete(Drupal\Core\Entity\EntityInterface $entity) {
- // Delete the entity's entry from a fictional table of all entities.
- db_delete('example_entity')
- ->condition('type', $entity->getEntityTypeId())
- ->condition('id', $entity->id())
- ->execute();
- }
- /**
- * Respond to entity revision deletion.
- *
- * This hook runs once the entity revision has been deleted from the storage.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object for the entity revision that has been deleted.
- *
- * @ingroup entity_crud
- * @see hook_ENTITY_TYPE_revision_delete()
- */
- function hook_entity_revision_delete(Drupal\Core\Entity\EntityInterface $entity) {
- $referenced_files_by_field = _editor_get_file_uuids_by_field($entity);
- foreach ($referenced_files_by_field as $field => $uuids) {
- _editor_delete_file_usage($uuids, $entity, 1);
- }
- }
- /**
- * Respond to entity revision deletion of a particular type.
- *
- * This hook runs once the entity revision has been deleted from the storage.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object for the entity revision that has been deleted.
- *
- * @ingroup entity_crud
- * @see hook_entity_revision_delete()
- */
- function hook_ENTITY_TYPE_revision_delete(Drupal\Core\Entity\EntityInterface $entity) {
- $referenced_files_by_field = _editor_get_file_uuids_by_field($entity);
- foreach ($referenced_files_by_field as $field => $uuids) {
- _editor_delete_file_usage($uuids, $entity, 1);
- }
- }
- /**
- * Act on entities being assembled before rendering.
- *
- * @param &$build
- * A renderable array representing the entity content. The module may add
- * elements to $build prior to rendering. The structure of $build is a
- * renderable array as expected by drupal_render().
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object.
- * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
- * The entity view display holding the display options configured for the
- * entity components.
- * @param $view_mode
- * The view mode the entity is rendered in.
- *
- * @see hook_entity_view_alter()
- * @see hook_ENTITY_TYPE_view()
- *
- * @ingroup entity_crud
- */
- function hook_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode) {
- // Only do the extra work if the component is configured to be displayed.
- // This assumes a 'mymodule_addition' extra field has been defined for the
- // entity bundle in hook_entity_extra_field_info().
- if ($display->getComponent('mymodule_addition')) {
- $build['mymodule_addition'] = [
- '#markup' => mymodule_addition($entity),
- '#theme' => 'mymodule_my_additional_field',
- ];
- }
- }
- /**
- * Act on entities of a particular type being assembled before rendering.
- *
- * @param &$build
- * A renderable array representing the entity content. The module may add
- * elements to $build prior to rendering. The structure of $build is a
- * renderable array as expected by drupal_render().
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object.
- * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
- * The entity view display holding the display options configured for the
- * entity components.
- * @param $view_mode
- * The view mode the entity is rendered in.
- *
- * @see hook_ENTITY_TYPE_view_alter()
- * @see hook_entity_view()
- *
- * @ingroup entity_crud
- */
- function hook_ENTITY_TYPE_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode) {
- // Only do the extra work if the component is configured to be displayed.
- // This assumes a 'mymodule_addition' extra field has been defined for the
- // entity bundle in hook_entity_extra_field_info().
- if ($display->getComponent('mymodule_addition')) {
- $build['mymodule_addition'] = [
- '#markup' => mymodule_addition($entity),
- '#theme' => 'mymodule_my_additional_field',
- ];
- }
- }
- /**
- * Alter the results of the entity build array.
- *
- * This hook is called after the content has been assembled in a structured
- * array and may be used for doing processing which requires that the complete
- * entity content structure has been built.
- *
- * If a module wishes to act on the rendered HTML of the entity rather than the
- * structured content array, it may use this hook to add a #post_render
- * callback. Alternatively, it could also implement hook_preprocess_HOOK() for
- * the particular entity type template, if there is one (e.g., node.html.twig).
- *
- * See the @link themeable Default theme implementations topic @endlink and
- * drupal_render() for details.
- *
- * @param array &$build
- * A renderable array representing the entity content.
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object being rendered.
- * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
- * The entity view display holding the display options configured for the
- * entity components.
- *
- * @ingroup entity_crud
- *
- * @see hook_entity_view()
- * @see hook_ENTITY_TYPE_view_alter()
- */
- function hook_entity_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
- if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
- // Change its weight.
- $build['an_additional_field']['#weight'] = -10;
- // Add a #post_render callback to act on the rendered HTML of the entity.
- $build['#post_render'][] = 'my_module_node_post_render';
- }
- }
- /**
- * Alter the results of the entity build array for a particular entity type.
- *
- * This hook is called after the content has been assembled in a structured
- * array and may be used for doing processing which requires that the complete
- * entity content structure has been built.
- *
- * If a module wishes to act on the rendered HTML of the entity rather than the
- * structured content array, it may use this hook to add a #post_render
- * callback. Alternatively, it could also implement hook_preprocess_HOOK() for
- * the particular entity type template, if there is one (e.g., node.html.twig).
- *
- * See the @link themeable Default theme implementations topic @endlink and
- * drupal_render() for details.
- *
- * @param array &$build
- * A renderable array representing the entity content.
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity object being rendered.
- * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
- * The entity view display holding the display options configured for the
- * entity components.
- *
- * @ingroup entity_crud
- *
- * @see hook_ENTITY_TYPE_view()
- * @see hook_entity_view_alter()
- */
- function hook_ENTITY_TYPE_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {
- if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
- // Change its weight.
- $build['an_additional_field']['#weight'] = -10;
- // Add a #post_render callback to act on the rendered HTML of the entity.
- $build['#post_render'][] = 'my_module_node_post_render';
- }
- }
- /**
- * Act on entities as they are being prepared for view.
- *
- * Allows you to operate on multiple entities as they are being prepared for
- * view. Only use this if attaching the data during the entity loading phase
- * is not appropriate, for example when attaching other 'entity' style objects.
- *
- * @param string $entity_type_id
- * The type of entities being viewed (i.e. node, user, comment).
- * @param array $entities
- * The entities keyed by entity ID.
- * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface[] $displays
- * The array of entity view displays holding the display options configured
- * for the entity components, keyed by bundle name.
- * @param string $view_mode
- * The view mode.
- *
- * @ingroup entity_crud
- */
- function hook_entity_prepare_view($entity_type_id, array $entities, array $displays, $view_mode) {
- // Load a specific node into the user object for later theming.
- if (!empty($entities) && $entity_type_id == 'user') {
- // Only do the extra work if the component is configured to be
- // displayed. This assumes a 'mymodule_addition' extra field has been
- // defined for the entity bundle in hook_entity_extra_field_info().
- $ids = [];
- foreach ($entities as $id => $entity) {
- if ($displays[$entity->bundle()]->getComponent('mymodule_addition')) {
- $ids[] = $id;
- }
- }
- if ($ids) {
- $nodes = mymodule_get_user_nodes($ids);
- foreach ($ids as $id) {
- $entities[$id]->user_node = $nodes[$id];
- }
- }
- }
- }
- /**
- * Change the view mode of an entity that is being displayed.
- *
- * @param string $view_mode
- * The view_mode that is to be used to display the entity.
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity that is being viewed.
- * @param array $context
- * Array with additional context information, currently only contains the
- * langcode the entity is viewed in.
- *
- * @ingroup entity_crud
- */
- function hook_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInterface $entity, $context) {
- // For nodes, change the view mode when it is teaser.
- if ($entity->getEntityTypeId() == 'node' && $view_mode == 'teaser') {
- $view_mode = 'my_custom_view_mode';
- }
- }
- /**
- * Alter entity renderable values before cache checking in drupal_render().
- *
- * Invoked for a specific entity type.
- *
- * The values in the #cache key of the renderable array are used to determine if
- * a cache entry exists for the entity's rendered output. Ideally only values
- * that pertain to caching should be altered in this hook.
- *
- * @param array &$build
- * A renderable array containing the entity's caching and view mode values.
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity that is being viewed.
- * @param string $view_mode
- * The view_mode that is to be used to display the entity.
- *
- * @see drupal_render()
- * @see \Drupal\Core\Entity\EntityViewBuilder
- * @see hook_entity_build_defaults_alter()
- *
- * @ingroup entity_crud
- */
- function hook_ENTITY_TYPE_build_defaults_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, $view_mode) {
- }
- /**
- * Alter entity renderable values before cache checking in drupal_render().
- *
- * The values in the #cache key of the renderable array are used to determine if
- * a cache entry exists for the entity's rendered output. Ideally only values
- * that pertain to caching should be altered in this hook.
- *
- * @param array &$build
- * A renderable array containing the entity's caching and view mode values.
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity that is being viewed.
- * @param string $view_mode
- * The view_mode that is to be used to display the entity.
- *
- * @see drupal_render()
- * @see \Drupal\Core\Entity\EntityViewBuilder
- * @see hook_ENTITY_TYPE_build_defaults_alter()
- *
- * @ingroup entity_crud
- */
- function hook_entity_build_defaults_alter(array &$build, \Drupal\Core\Entity\EntityInterface $entity, $view_mode) {
- }
- /**
- * Alter the settings used for displaying an entity.
- *
- * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
- * The entity view display that will be used to display the entity
- * components.
- * @param array $context
- * An associative array containing:
- * - entity_type: The entity type, e.g., 'node' or 'user'.
- * - bundle: The bundle, e.g., 'page' or 'article'.
- * - view_mode: The view mode, e.g., 'full', 'teaser', etc.
- *
- * @ingroup entity_crud
- */
- function hook_entity_view_display_alter(\Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, array $context) {
- // Leave field labels out of the search index.
- if ($context['entity_type'] == 'node' && $context['view_mode'] == 'search_index') {
- foreach ($display->getComponents() as $name => $options) {
- if (isset($options['label'])) {
- $options['label'] = 'hidden';
- $display->setComponent($name, $options);
- }
- }
- }
- }
- /**
- * Alter the render array generated by an EntityDisplay for an entity.
- *
- * @param array $build
- * The renderable array generated by the EntityDisplay.
- * @param array $context
- * An associative array containing:
- * - entity: The entity being rendered.
- * - view_mode: The view mode; for example, 'full' or 'teaser'.
- * - display: The EntityDisplay holding the display options.
- *
- * @ingroup entity_crud
- */
- function hook_entity_display_build_alter(&$build, $context) {
- // Append RDF term mappings on displayed taxonomy links.
- foreach (Element::children($build) as $field_name) {
- $element = &$build[$field_name];
- if ($element['#field_type'] == 'entity_reference' && $element['#formatter'] == 'entity_reference_label') {
- foreach ($element['#items'] as $delta => $item) {
- $term = $item->entity;
- if (!empty($term->rdf_mapping['rdftype'])) {
- $element[$delta]['#options']['attributes']['typeof'] = $term->rdf_mapping['rdftype'];
- }
- if (!empty($term->rdf_mapping['name']['predicates'])) {
- $element[$delta]['#options']['attributes']['property'] = $term->rdf_mapping['name']['predicates'];
- }
- }
- }
- }
- }
- /**
- * Acts on an entity object about to be shown on an entity form.
- *
- * This can be typically used to pre-fill entity values or change the form state
- * before the entity form is built. It is invoked just once when first building
- * the entity form. Rebuilds will not trigger a new invocation.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity that is about to be shown on the form.
- * @param $operation
- * The current operation.
- * @param \Drupal\Core\Form\FormStateInterface $form_state
- * The current state of the form.
- *
- * @see \Drupal\Core\Entity\EntityForm::prepareEntity()
- * @see hook_ENTITY_TYPE_prepare_form()
- *
- * @ingroup entity_crud
- */
- function hook_entity_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Form\FormStateInterface $form_state) {
- if ($operation == 'edit') {
- $entity->label->value = 'Altered label';
- $form_state->set('label_altered', TRUE);
- }
- }
- /**
- * Acts on a particular type of entity object about to be in an entity form.
- *
- * This can be typically used to pre-fill entity values or change the form state
- * before the entity form is built. It is invoked just once when first building
- * the entity form. Rebuilds will not trigger a new invocation.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity that is about to be shown on the form.
- * @param $operation
- * The current operation.
- * @param \Drupal\Core\Form\FormStateInterface $form_state
- * The current state of the form.
- *
- * @see \Drupal\Core\Entity\EntityForm::prepareEntity()
- * @see hook_entity_prepare_form()
- *
- * @ingroup entity_crud
- */
- function hook_ENTITY_TYPE_prepare_form(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Form\FormStateInterface $form_state) {
- if ($operation == 'edit') {
- $entity->label->value = 'Altered label';
- $form_state->set('label_altered', TRUE);
- }
- }
- /**
- * Alter the settings used for displaying an entity form.
- *
- * @param \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display
- * The entity_form_display object that will be used to display the entity form
- * components.
- * @param array $context
- * An associative array containing:
- * - entity_type: The entity type, e.g., 'node' or 'user'.
- * - bundle: The bundle, e.g., 'page' or 'article'.
- * - form_mode: The form mode; e.g., 'default', 'profile', 'register', etc.
- *
- * @ingroup entity_crud
- */
- function hook_entity_form_display_alter(\Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display, array $context) {
- // Hide the 'user_picture' field from the register form.
- if ($context['entity_type'] == 'user' && $context['form_mode'] == 'register') {
- $form_display->setComponent('user_picture', [
- 'region' => 'hidden',
- ]);
- }
- }
- /**
- * Provides custom base field definitions for a content entity type.
- *
- * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
- * The entity type definition.
- *
- * @return \Drupal\Core\Field\FieldDefinitionInterface[]
- * An array of field definitions, keyed by field name.
- *
- * @see hook_entity_base_field_info_alter()
- * @see hook_entity_bundle_field_info()
- * @see hook_entity_bundle_field_info_alter()
- * @see \Drupal\Core\Field\FieldDefinitionInterface
- * @see \Drupal\Core\Entity\EntityManagerInterface::getFieldDefinitions()
- */
- function hook_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) {
- if ($entity_type->id() == 'node') {
- $fields = [];
- $fields['mymodule_text'] = BaseFieldDefinition::create('string')
- ->setLabel(t('The text'))
- ->setDescription(t('A text property added by mymodule.'))
- ->setComputed(TRUE)
- ->setClass('\Drupal\mymodule\EntityComputedText');
- return $fields;
- }
- }
- /**
- * Alter base field definitions for a content entity type.
- *
- * @param \Drupal\Core\Field\FieldDefinitionInterface[] $fields
- * The array of base field definitions for the entity type.
- * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
- * The entity type definition.
- *
- * @see hook_entity_base_field_info()
- * @see hook_entity_bundle_field_info()
- * @see hook_entity_bundle_field_info_alter()
- *
- * @todo WARNING: This hook will be changed in
- * https://www.drupal.org/node/2346329.
- */
- function hook_entity_base_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type) {
- // Alter the mymodule_text field to use a custom class.
- if ($entity_type->id() == 'node' && !empty($fields['mymodule_text'])) {
- $fields['mymodule_text']->setClass('\Drupal\anothermodule\EntityComputedText');
- }
- }
- /**
- * Provides field definitions for a specific bundle within an entity type.
- *
- * Bundle fields either have to override an existing base field, or need to
- * provide a field storage definition via hook_entity_field_storage_info()
- * unless they are computed.
- *
- * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
- * The entity type definition.
- * @param string $bundle
- * The bundle.
- * @param \Drupal\Core\Field\FieldDefinitionInterface[] $base_field_definitions
- * The list of base field definitions for the entity type.
- *
- * @return \Drupal\Core\Field\FieldDefinitionInterface[]
- * An array of bundle field definitions, keyed by field name.
- *
- * @see hook_entity_base_field_info()
- * @see hook_entity_base_field_info_alter()
- * @see hook_entity_field_storage_info()
- * @see hook_entity_field_storage_info_alter()
- * @see hook_entity_bundle_field_info_alter()
- * @see \Drupal\Core\Field\FieldDefinitionInterface
- * @see \Drupal\Core\Entity\EntityManagerInterface::getFieldDefinitions()
- *
- * @todo WARNING: This hook will be changed in
- * https://www.drupal.org/node/2346347.
- */
- function hook_entity_bundle_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
- // Add a property only to nodes of the 'article' bundle.
- if ($entity_type->id() == 'node' && $bundle == 'article') {
- $fields = [];
- $fields['mymodule_text_more'] = BaseFieldDefinition::create('string')
- ->setLabel(t('More text'))
- ->setComputed(TRUE)
- ->setClass('\Drupal\mymodule\EntityComputedMoreText');
- return $fields;
- }
- }
- /**
- * Alter bundle field definitions.
- *
- * @param \Drupal\Core\Field\FieldDefinitionInterface[] $fields
- * The array of bundle field definitions.
- * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
- * The entity type definition.
- * @param string $bundle
- * The bundle.
- *
- * @see hook_entity_base_field_info()
- * @see hook_entity_base_field_info_alter()
- * @see hook_entity_bundle_field_info()
- *
- * @todo WARNING: This hook will be changed in
- * https://www.drupal.org/node/2346347.
- */
- function hook_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) {
- if ($entity_type->id() == 'node' && $bundle == 'article' && !empty($fields['mymodule_text'])) {
- // Alter the mymodule_text field to use a custom class.
- $fields['mymodule_text']->setClass('\Drupal\anothermodule\EntityComputedText');
- }
- }
- /**
- * Provides field storage definitions for a content entity type.
- *
- * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
- * The entity type definition.
- *
- * @return \Drupal\Core\Field\FieldStorageDefinitionInterface[]
- * An array of field storage definitions, keyed by field name.
- *
- * @see hook_entity_field_storage_info_alter()
- * @see \Drupal\Core\Field\FieldStorageDefinitionInterface
- * @see \Drupal\Core\Entity\EntityManagerInterface::getFieldStorageDefinitions()
- */
- function hook_entity_field_storage_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) {
- if (\Drupal::entityManager()->getStorage($entity_type->id()) instanceof DynamicallyFieldableEntityStorageInterface) {
- // Query by filtering on the ID as this is more efficient than filtering
- // on the entity_type property directly.
- $ids = \Drupal::entityQuery('field_storage_config')
- ->condition('id', $entity_type->id() . '.', 'STARTS_WITH')
- ->execute();
- // Fetch all fields and key them by field name.
- $field_storages = FieldStorageConfig::loadMultiple($ids);
- $result = [];
- foreach ($field_storages as $field_storage) {
- $result[$field_storage->getName()] = $field_storage;
- }
- return $result;
- }
- }
- /**
- * Alter field storage definitions for a content entity type.
- *
- * @param \Drupal\Core\Field\FieldStorageDefinitionInterface[] $fields
- * The array of field storage definitions for the entity type.
- * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
- * The entity type definition.
- *
- * @see hook_entity_field_storage_info()
- */
- function hook_entity_field_storage_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type) {
- // Alter the max_length setting.
- if ($entity_type->id() == 'node' && !empty($fields['mymodule_text'])) {
- $fields['mymodule_text']->setSetting('max_length', 128);
- }
- }
- /**
- * Declares entity operations.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity on which the linked operations will be performed.
- *
- * @return array
- * An operations array as returned by
- * EntityListBuilderInterface::getOperations().
- *
- * @see \Drupal\Core\Entity\EntityListBuilderInterface::getOperations()
- */
- function hook_entity_operation(\Drupal\Core\Entity\EntityInterface $entity) {
- $operations = [];
- $operations['translate'] = [
- 'title' => t('Translate'),
- 'url' => \Drupal\Core\Url::fromRoute('foo_module.entity.translate'),
- 'weight' => 50,
- ];
- return $operations;
- }
- /**
- * Alter entity operations.
- *
- * @param array $operations
- * Operations array as returned by
- * \Drupal\Core\Entity\EntityListBuilderInterface::getOperations().
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity on which the linked operations will be performed.
- */
- function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\EntityInterface $entity) {
- // Alter the title and weight.
- $operations['translate']['title'] = t('Translate @entity_type', [
- '@entity_type' => $entity->getEntityTypeId(),
- ]);
- $operations['translate']['weight'] = 99;
- }
- /**
- * Control access to fields.
- *
- * This hook is invoked from
- * \Drupal\Core\Entity\EntityAccessControlHandler::fieldAccess() to let modules
- * grant or deny operations on fields.
- *
- * @param string $operation
- * The operation to be performed. See
- * \Drupal\Core\Entity\EntityAccessControlHandlerInterface::fieldAccess()
- * for possible values.
- * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
- * The field definition.
- * @param \Drupal\Core\Session\AccountInterface $account
- * The user account to check.
- * @param \Drupal\Core\Field\FieldItemListInterface $items
- * (optional) The entity field object on which the operation is to be
- * performed.
- *
- * @return \Drupal\Core\Access\AccessResultInterface
- * The access result.
- *
- * @see \Drupal\Core\Entity\EntityAccessControlHandlerInterface::fieldAccess()
- */
- function hook_entity_field_access($operation, \Drupal\Core\Field\FieldDefinitionInterface $field_definition, \Drupal\Core\Session\AccountInterface $account, \Drupal\Core\Field\FieldItemListInterface $items = NULL) {
- if ($field_definition->getName() == 'field_of_interest' && $operation == 'edit') {
- return AccessResult::allowedIfHasPermission($account, 'update field of interest');
- }
- return AccessResult::neutral();
- }
- /**
- * Alter the default access behavior for a given field.
- *
- * Use this hook to override access grants from another module. Note that the
- * original default access flag is masked under the ':default' key.
- *
- * @param \Drupal\Core\Access\AccessResultInterface[] $grants
- * An array of grants gathered by hook_entity_field_access(). The array is
- * keyed by the module that defines the field's access control; the values are
- * grant responses for each module (\Drupal\Core\Access\AccessResult).
- * @param array $context
- * Context array on the performed operation with the following keys:
- * - operation: The operation to be performed (string).
- * - field_definition: The field definition object
- * (\Drupal\Core\Field\FieldDefinitionInterface)
- * - account: The user account to check access for
- * (Drupal\user\Entity\User).
- * - items: (optional) The entity field items
- * (\Drupal\Core\Field\FieldItemListInterface).
- */
- function hook_entity_field_access_alter(array &$grants, array $context) {
- /** @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */
- $field_definition = $context['field_definition'];
- if ($field_definition->getName() == 'field_of_interest' && $grants['node']->isForbidden()) {
- // Override node module's restriction to no opinion (neither allowed nor
- // forbidden). We don't want to provide our own access hook, we only want to
- // take out node module's part in the access handling of this field. We also
- // don't want to switch node module's grant to
- // AccessResultInterface::isAllowed() , because the grants of other modules
- // should still decide on their own if this field is accessible or not
- $grants['node'] = AccessResult::neutral()->inheritCacheability($grants['node']);
- }
- }
- /**
- * Acts when initializing a fieldable entity object.
- *
- * This hook runs after a new entity object or a new entity translation object
- * has just been instantiated. It can be used to set initial values, e.g. to
- * provide defaults.
- *
- * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
- * The entity object.
- *
- * @ingroup entity_crud
- * @see hook_ENTITY_TYPE_field_values_init()
- */
- function hook_entity_field_values_init(\Drupal\Core\Entity\FieldableEntityInterface $entity) {
- if ($entity instanceof \Drupal\Core\Entity\ContentEntityInterface && !$entity->foo->value) {
- $entity->foo->value = 'some_initial_value';
- }
- }
- /**
- * Acts when initializing a fieldable entity object.
- *
- * This hook runs after a new entity object or a new entity translation object
- * has just been instantiated. It can be used to set initial values, e.g. to
- * provide defaults.
- *
- * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
- * The entity object.
- *
- * @ingroup entity_crud
- * @see hook_entity_field_values_init()
- */
- function hook_ENTITY_TYPE_field_values_init(\Drupal\Core\Entity\FieldableEntityInterface $entity) {
- if (!$entity->foo->value) {
- $entity->foo->value = 'some_initial_value';
- }
- }
- /**
- * Exposes "pseudo-field" components on content entities.
- *
- * Field UI's "Manage fields" and "Manage display" pages let users re-order
- * fields, but also non-field components. For nodes, these include elements
- * exposed by modules through hook_form_alter(), for instance.
- *
- * Content entities or modules that want to have their components supported
- * should expose them using this hook. The user-defined settings (weight,
- * visible) are automatically applied when entities or entity forms are
- * rendered.
- *
- * @see hook_entity_extra_field_info_alter()
- *
- * @return array
- * The array structure is identical to that of the return value of
- * \Drupal\Core\Entity\EntityFieldManagerInterface::getExtraFields().
- */
- function hook_entity_extra_field_info() {
- $extra = [];
- $module_language_enabled = \Drupal::moduleHandler()->moduleExists('language');
- $description = t('Node module element');
- foreach (NodeType::loadMultiple() as $bundle) {
- // Add also the 'language' select if Language module is enabled and the
- // bundle has multilingual support.
- // Visibility of the ordering of the language selector is the same as on the
- // node/add form.
- if ($module_language_enabled) {
- $configuration = ContentLanguageSettings::loadByEntityTypeBundle('node', $bundle->id());
- if ($configuration->isLanguageAlterable()) {
- $extra['node'][$bundle->id()]['form']['language'] = [
- 'label' => t('Language'),
- 'description' => $description,
- 'weight' => 0,
- ];
- }
- }
- $extra['node'][$bundle->id()]['display']['language'] = [
- 'label' => t('Language'),
- 'description' => $description,
- 'weight' => 0,
- 'visible' => FALSE,
- ];
- }
- return $extra;
- }
- /**
- * Alter "pseudo-field" components on content entities.
- *
- * @param array $info
- * The array structure is identical to that of the return value of
- * \Drupal\Core\Entity\EntityManagerInterface::getExtraFields().
- *
- * @see hook_entity_extra_field_info()
- */
- function hook_entity_extra_field_info_alter(&$info) {
- // Force node title to always be at the top of the list by default.
- foreach (NodeType::loadMultiple() as $bundle) {
- if (isset($info['node'][$bundle->id()]['form']['title'])) {
- $info['node'][$bundle->id()]['form']['title']['weight'] = -20;
- }
- }
- }
- /**
- * @} End of "addtogroup hooks".
- */
|