X-Git-Url: http://aleph1.co.uk/gitweb/?a=blobdiff_plain;f=web%2Fcore%2Flib%2FDrupal%2FCore%2FEntity%2Fentity.api.php;h=ac137330f8dc7e1ae1e82663dca095741c7ef76f;hb=4f1b9b4ab48a8498afac9e2213a02a23ccf4a06c;hp=41c854ad2952960f8cbe47d0e6975054e80467e3;hpb=9917807b03b64faf00f6a1f29dcb6eafc454efa5;p=yaffs-website diff --git a/web/core/lib/Drupal/Core/Entity/entity.api.php b/web/core/lib/Drupal/Core/Entity/entity.api.php index 41c854ad2..ac137330f 100644 --- a/web/core/lib/Drupal/Core/Entity/entity.api.php +++ b/web/core/lib/Drupal/Core/Entity/entity.api.php @@ -68,6 +68,57 @@ use Drupal\node\Entity\NodeType; * - 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 @@ -84,6 +135,10 @@ use Drupal\node\Entity\NodeType; * 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. * @@ -113,16 +168,34 @@ use Drupal\node\Entity\NodeType; * @endcode * This involves the same hooks and operations as regular entity loading. * - * @section entities_revisions_translations Entities, revisions and translations + * 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 * - * A translation is not a revision and a revision is not necessarily a - * translation. Revisions and translations are the two axes on the "spreadsheet" - * of an entity. If you use the built-in UI and have revisions enabled, then a - * new translation change would create a new revision (with a copy of all data - * for other languages in that revision). If an entity does not use revisions or - * the entity is being modified via the API, then multiple translations can be - * modified in a single revision. Conceptually, the revisions are columns on the - * spreadsheet and translations are rows. + * 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, @@ -154,6 +227,10 @@ use Drupal\node\Entity\NodeType; * - 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: @@ -513,7 +590,7 @@ use Drupal\node\Entity\NodeType; * // rules will be used. * $build = $view_builder->view($entity, 'view_mode_name', $language->getId()); * // $build is a render array. - * $rendered = drupal_render($build); + * $rendered = \Drupal::service('renderer')->render($build); * @endcode * * @section sec_access Access checking on entities @@ -832,6 +909,54 @@ function hook_ENTITY_TYPE_create(\Drupal\Core\Entity\EntityInterface $entity) { \Drupal::logger('example')->info('ENTITY_TYPE created: @label', ['@label' => $entity->label()]); } +/** + * Respond to entity revision creation. + * + * @param \Drupal\Core\Entity\EntityInterface $new_revision + * The new revision that was created. + * @param \Drupal\Core\Entity\EntityInterface $entity + * The original entity that was used to create the revision from. + * @param bool|null $keep_untranslatable_fields + * Whether untranslatable field values were kept (TRUE) or copied from the + * default revision (FALSE) when generating a merged revision. If no value was + * explicitly specified (NULL), a default value of TRUE should be assumed if + * the provided entity is the default translation and untranslatable fields + * should only affect the default translation, FALSE otherwise. + * + * @ingroup entity_crud + * @see \Drupal\Core\Entity\RevisionableStorageInterface::createRevision() + * @see \Drupal\Core\Entity\TranslatableRevisionableStorageInterface::createRevision() + */ +function hook_entity_revision_create(Drupal\Core\Entity\EntityInterface $new_revision, Drupal\Core\Entity\EntityInterface $entity, $keep_untranslatable_fields) { + // Retain the value from an untranslatable field, which are by default + // synchronized from the default revision. + $new_revision->set('untranslatable_field', $entity->get('untranslatable_field')); +} + +/** + * Respond to entity revision creation. + * + * @param \Drupal\Core\Entity\EntityInterface $new_revision + * The new revision that was created. + * @param \Drupal\Core\Entity\EntityInterface $entity + * The original entity that was used to create the revision from. + * @param bool|null $keep_untranslatable_fields + * Whether untranslatable field values were kept (TRUE) or copied from the + * default revision (FALSE) when generating a merged revision. If no value was + * explicitly specified (NULL), a default value of TRUE should be assumed if + * the provided entity is the default translation and untranslatable fields + * should only affect the default translation, FALSE otherwise. + * + * @ingroup entity_crud + * @see \Drupal\Core\Entity\RevisionableStorageInterface::createRevision() + * @see \Drupal\Core\Entity\TranslatableRevisionableStorageInterface::createRevision() + */ +function hook_ENTITY_TYPE_revision_create(Drupal\Core\Entity\EntityInterface $new_revision, Drupal\Core\Entity\EntityInterface $entity, $keep_untranslatable_fields) { + // Retain the value from an untranslatable field, which are by default + // synchronized from the default revision. + $new_revision->set('untranslatable_field', $entity->get('untranslatable_field')); +} + /** * Act on entities when loaded. * @@ -1282,7 +1407,8 @@ function hook_ENTITY_TYPE_revision_delete(Drupal\Core\Entity\EntityInterface $en * @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(). + * renderable array as expected by + * \Drupal\Core\Render\RendererInterface::render(). * @param \Drupal\Core\Entity\EntityInterface $entity * The entity object. * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display @@ -1314,7 +1440,8 @@ function hook_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $en * @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(). + * renderable array as expected by + * \Drupal\Core\Render\RendererInterface::render(). * @param \Drupal\Core\Entity\EntityInterface $entity * The entity object. * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display @@ -1492,7 +1619,7 @@ function hook_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInter * @param string $view_mode * The view_mode that is to be used to display the entity. * - * @see drupal_render() + * @see \Drupal\Core\Render\RendererInterface::render() * @see \Drupal\Core\Entity\EntityViewBuilder * @see hook_entity_build_defaults_alter() * @@ -1516,7 +1643,7 @@ function hook_ENTITY_TYPE_build_defaults_alter(array &$build, \Drupal\Core\Entit * @param string $view_mode * The view_mode that is to be used to display the entity. * - * @see drupal_render() + * @see \Drupal\Core\Render\RendererInterface::render() * @see \Drupal\Core\Entity\EntityViewBuilder * @see hook_ENTITY_TYPE_build_defaults_alter() * @@ -1876,8 +2003,9 @@ function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\Ent * @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. + * (optional) The entity field object for which to check access, or NULL if + * access is checked for the field definition, without any specific value + * available. Defaults to NULL. * * @return \Drupal\Core\Access\AccessResultInterface * The access result.