Issue #2929496 by plach, hchonov, timmillwood, catch, Wim Leers, amateescu, Calystod, andypost: Add dedicated interfaces to group methods dealing with revision translation and clean up the related documentation
parent
2e16f2a35d
commit
8e9f1b6120
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
namespace Drupal\Core\Entity;
|
namespace Drupal\Core\Entity;
|
||||||
|
|
||||||
use Drupal\Core\TypedData\TranslatableInterface;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a common interface for all content entity objects.
|
* Defines a common interface for all content entity objects.
|
||||||
*
|
*
|
||||||
|
@ -20,70 +18,7 @@ use Drupal\Core\TypedData\TranslatableInterface;
|
||||||
*
|
*
|
||||||
* @ingroup entity_api
|
* @ingroup entity_api
|
||||||
*/
|
*/
|
||||||
interface ContentEntityInterface extends \Traversable, FieldableEntityInterface, RevisionableInterface, TranslatableInterface {
|
interface ContentEntityInterface extends \Traversable, FieldableEntityInterface, TranslatableRevisionableInterface {
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if the current translation of the entity has unsaved changes.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
* TRUE if the current translation of the entity has changes.
|
|
||||||
*/
|
|
||||||
public function hasTranslationChanges();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Marks the current revision translation as affected.
|
|
||||||
*
|
|
||||||
* Setting the revision translation affected flag through the setter or
|
|
||||||
* through the field directly will always enforce it, which will be used by
|
|
||||||
* the entity storage to determine if the flag should be recomputed or the set
|
|
||||||
* value should be used instead.
|
|
||||||
* @see \Drupal\Core\Entity\ContentEntityStorageBase::populateAffectedRevisionTranslations()
|
|
||||||
*
|
|
||||||
* @param bool|null $affected
|
|
||||||
* The flag value. A NULL value can be specified to reset the current value
|
|
||||||
* and make sure a new value will be computed by the system.
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setRevisionTranslationAffected($affected);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the current translation is affected by the current revision.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
* TRUE if the entity object is affected by the current revision, FALSE
|
|
||||||
* otherwise.
|
|
||||||
*/
|
|
||||||
public function isRevisionTranslationAffected();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the revision translation affected flag value has been enforced.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
* TRUE if revision translation affected flag is enforced, FALSE otherwise.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
public function isRevisionTranslationAffectedEnforced();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enforces the revision translation affected flag value.
|
|
||||||
*
|
|
||||||
* Note that this method call will not have any influence on the storage if
|
|
||||||
* the value of the revision translation affected flag is NULL which is used
|
|
||||||
* as an indication for the storage to recompute the flag.
|
|
||||||
* @see \Drupal\Core\Entity\ContentEntityInterface::setRevisionTranslationAffected()
|
|
||||||
*
|
|
||||||
* @param bool $enforced
|
|
||||||
* If TRUE, the value of the revision translation affected flag will be
|
|
||||||
* enforced so that on entity save the entity storage will not recompute it.
|
|
||||||
* Otherwise the storage will recompute it.
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
public function setRevisionTranslationAffectedEnforced($enforced);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the loaded Revision ID of the entity.
|
* Gets the loaded Revision ID of the entity.
|
||||||
|
|
|
@ -5,24 +5,7 @@ namespace Drupal\Core\Entity;
|
||||||
/**
|
/**
|
||||||
* A storage that supports content entity types.
|
* A storage that supports content entity types.
|
||||||
*/
|
*/
|
||||||
interface ContentEntityStorageInterface extends EntityStorageInterface, RevisionableStorageInterface {
|
interface ContentEntityStorageInterface extends EntityStorageInterface, TranslatableRevisionableStorageInterface {
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new entity translation object, without permanently saving it.
|
|
||||||
*
|
|
||||||
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
|
|
||||||
* The entity object being translated.
|
|
||||||
* @param string $langcode
|
|
||||||
* The translation language code.
|
|
||||||
* @param array $values
|
|
||||||
* (optional) An associative array of initial field values keyed by field
|
|
||||||
* name. If none is provided default values will be applied.
|
|
||||||
*
|
|
||||||
* @return \Drupal\Core\Entity\ContentEntityInterface
|
|
||||||
* A new entity translation object.
|
|
||||||
*/
|
|
||||||
public function createTranslation(ContentEntityInterface $entity, $langcode, array $values = []);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an entity with sample field values.
|
* Creates an entity with sample field values.
|
||||||
|
|
|
@ -8,7 +8,7 @@ use Drupal\Core\Entity\EntityDisplayPluginCollection;
|
||||||
use Drupal\Core\Entity\EntityStorageInterface;
|
use Drupal\Core\Entity\EntityStorageInterface;
|
||||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||||
use Drupal\Core\Entity\EntityDisplayBase;
|
use Drupal\Core\Entity\EntityDisplayBase;
|
||||||
use Drupal\Core\TypedData\TranslatableInterface;
|
use Drupal\Core\TypedData\TranslatableInterface as TranslatableDataInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration entity that contains display options for all components of a
|
* Configuration entity that contains display options for all components of a
|
||||||
|
@ -253,7 +253,7 @@ class EntityViewDisplay extends EntityDisplayBase implements EntityViewDisplayIn
|
||||||
// those values using:
|
// those values using:
|
||||||
// - the entity language if the entity is translatable,
|
// - the entity language if the entity is translatable,
|
||||||
// - the current "content language" otherwise.
|
// - the current "content language" otherwise.
|
||||||
if ($entity instanceof TranslatableInterface && $entity->isTranslatable()) {
|
if ($entity instanceof TranslatableDataInterface && $entity->isTranslatable()) {
|
||||||
$view_langcode = $entity->language()->getId();
|
$view_langcode = $entity->language()->getId();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace Drupal\Core\Entity;
|
||||||
use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
|
use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
|
||||||
use Drupal\Core\Language\LanguageInterface;
|
use Drupal\Core\Language\LanguageInterface;
|
||||||
use Drupal\Core\Language\LanguageManagerInterface;
|
use Drupal\Core\Language\LanguageManagerInterface;
|
||||||
use Drupal\Core\TypedData\TranslatableInterface;
|
use Drupal\Core\TypedData\TranslatableInterface as TranslatableDataInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides several mechanisms for retrieving entities.
|
* Provides several mechanisms for retrieving entities.
|
||||||
|
@ -82,7 +82,7 @@ class EntityRepository implements EntityRepositoryInterface {
|
||||||
public function getTranslationFromContext(EntityInterface $entity, $langcode = NULL, $context = []) {
|
public function getTranslationFromContext(EntityInterface $entity, $langcode = NULL, $context = []) {
|
||||||
$translation = $entity;
|
$translation = $entity;
|
||||||
|
|
||||||
if ($entity instanceof TranslatableInterface && count($entity->getTranslationLanguages()) > 1) {
|
if ($entity instanceof TranslatableDataInterface && count($entity->getTranslationLanguages()) > 1) {
|
||||||
if (empty($langcode)) {
|
if (empty($langcode)) {
|
||||||
$langcode = $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId();
|
$langcode = $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId();
|
||||||
$entity->addCacheContexts(['languages:' . LanguageInterface::TYPE_CONTENT]);
|
$entity->addCacheContexts(['languages:' . LanguageInterface::TYPE_CONTENT]);
|
||||||
|
|
|
@ -11,7 +11,7 @@ use Drupal\Core\Field\FieldItemListInterface;
|
||||||
use Drupal\Core\Language\LanguageManagerInterface;
|
use Drupal\Core\Language\LanguageManagerInterface;
|
||||||
use Drupal\Core\Render\Element;
|
use Drupal\Core\Render\Element;
|
||||||
use Drupal\Core\Theme\Registry;
|
use Drupal\Core\Theme\Registry;
|
||||||
use Drupal\Core\TypedData\TranslatableInterface;
|
use Drupal\Core\TypedData\TranslatableInterface as TranslatableDataInterface;
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -189,7 +189,7 @@ class EntityViewBuilder extends EntityHandlerBase implements EntityHandlerInterf
|
||||||
'bin' => $this->cacheBin,
|
'bin' => $this->cacheBin,
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($entity instanceof TranslatableInterface && count($entity->getTranslationLanguages()) > 1) {
|
if ($entity instanceof TranslatableDataInterface && count($entity->getTranslationLanguages()) > 1) {
|
||||||
$build['#cache']['keys'][] = $entity->language()->getId();
|
$build['#cache']['keys'][] = $entity->language()->getId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\Core\Entity;
|
||||||
|
|
||||||
|
use Drupal\Core\TypedData\TranslatableInterface as TranslatableDataInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides methods for an entity to support translation.
|
||||||
|
*/
|
||||||
|
interface TranslatableInterface extends TranslatableDataInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the current translation of the entity has unsaved changes.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
* TRUE if the current translation of the entity has changes.
|
||||||
|
*/
|
||||||
|
public function hasTranslationChanges();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\Core\Entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides methods for an entity to support revision translation.
|
||||||
|
*/
|
||||||
|
interface TranslatableRevisionableInterface extends TranslatableInterface, RevisionableInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the current revision translation as affected.
|
||||||
|
*
|
||||||
|
* Setting the revision translation affected flag through the setter or
|
||||||
|
* through the field directly will always enforce it, which will be used by
|
||||||
|
* the entity storage to determine if the flag should be recomputed or the set
|
||||||
|
* value should be used instead.
|
||||||
|
* @see \Drupal\Core\Entity\ContentEntityStorageBase::populateAffectedRevisionTranslations()
|
||||||
|
*
|
||||||
|
* @param bool|null $affected
|
||||||
|
* The flag value. A NULL value can be specified to reset the current value
|
||||||
|
* and make sure a new value will be computed by the system.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setRevisionTranslationAffected($affected);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the current translation is affected by the current revision.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
* TRUE if the entity object is affected by the current revision, FALSE
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
public function isRevisionTranslationAffected();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the revision translation affected flag value has been enforced.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
* TRUE if revision translation affected flag is enforced, FALSE otherwise.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public function isRevisionTranslationAffectedEnforced();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enforces the revision translation affected flag value.
|
||||||
|
*
|
||||||
|
* Note that this method call will not have any influence on the storage if
|
||||||
|
* the value of the revision translation affected flag is NULL which is used
|
||||||
|
* as an indication for the storage to recompute the flag.
|
||||||
|
* @see \Drupal\Core\Entity\ContentEntityInterface::setRevisionTranslationAffected()
|
||||||
|
*
|
||||||
|
* @param bool $enforced
|
||||||
|
* If TRUE, the value of the revision translation affected flag will be
|
||||||
|
* enforced so that on entity save the entity storage will not recompute it.
|
||||||
|
* Otherwise the storage will recompute it.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public function setRevisionTranslationAffectedEnforced($enforced);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\Core\Entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A storage that supports translatable and revisionable entity types.
|
||||||
|
*/
|
||||||
|
interface TranslatableRevisionableStorageInterface extends TranslatableStorageInterface, RevisionableStorageInterface {
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\Core\Entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A storage that supports translatable entity types.
|
||||||
|
*/
|
||||||
|
interface TranslatableStorageInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new entity translation object, without permanently saving it.
|
||||||
|
*
|
||||||
|
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
|
||||||
|
* The entity object being translated.
|
||||||
|
* @param string $langcode
|
||||||
|
* The translation language code.
|
||||||
|
* @param array $values
|
||||||
|
* (optional) An associative array of initial field values keyed by field
|
||||||
|
* name. If none is provided default values will be applied.
|
||||||
|
*
|
||||||
|
* @return \Drupal\Core\Entity\ContentEntityInterface
|
||||||
|
* Another instance of the specified entity object class with the specified
|
||||||
|
* active language and initial values.
|
||||||
|
*
|
||||||
|
* @todo Consider accepting \Drupal\Core\Entity\TranslatableInterface as first
|
||||||
|
* parameter. See https://www.drupal.org/project/drupal/issues/2932049.
|
||||||
|
*/
|
||||||
|
public function createTranslation(ContentEntityInterface $entity, $langcode, array $values = []);
|
||||||
|
|
||||||
|
}
|
|
@ -68,6 +68,57 @@ use Drupal\node\Entity\NodeType;
|
||||||
* - During many operations, static methods are called on the entity class,
|
* - During many operations, static methods are called on the entity class,
|
||||||
* which implements \Drupal\Entity\EntityInterface.
|
* 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
|
* @section create Create operations
|
||||||
* To create an entity:
|
* To create an entity:
|
||||||
* @code
|
* @code
|
||||||
|
@ -84,6 +135,10 @@ use Drupal\node\Entity\NodeType;
|
||||||
* Hooks invoked during the create operation:
|
* Hooks invoked during the create operation:
|
||||||
* - hook_ENTITY_TYPE_create()
|
* - hook_ENTITY_TYPE_create()
|
||||||
* - hook_entity_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.
|
* See @ref save below for the save portion of the operation.
|
||||||
*
|
*
|
||||||
|
@ -113,17 +168,6 @@ use Drupal\node\Entity\NodeType;
|
||||||
* @endcode
|
* @endcode
|
||||||
* This involves the same hooks and operations as regular entity loading.
|
* This involves the same hooks and operations as regular entity loading.
|
||||||
*
|
*
|
||||||
* @section entities_revisions_translations Entities, revisions and translations
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* @section save Save operations
|
* @section save Save operations
|
||||||
* To update an existing entity, you will need to load it, change properties,
|
* 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
|
* and then save; as described above, when creating a new entity, you will also
|
||||||
|
|
Loading…
Reference in New Issue