X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=web%2Fcore%2Flib%2FDrupal%2FCore%2FEntity%2FContentEntityBase.php;fp=web%2Fcore%2Flib%2FDrupal%2FCore%2FEntity%2FContentEntityBase.php;h=6b999c6977f5f2a0252387b3f8fac7c535579ced;hp=43db12fd796e59dab5d4d8ebc5004e395ef88931;hb=af6d1fb995500ae68849458ee10d66abbdcfb252;hpb=680c79a86e3ed402f263faeac92e89fb6d9edcc0 diff --git a/web/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/web/core/lib/Drupal/Core/Entity/ContentEntityBase.php index 43db12fd7..6b999c697 100644 --- a/web/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/web/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -20,6 +20,10 @@ use Drupal\Core\TypedData\TypedDataInterface; */ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, ContentEntityInterface, TranslationStatusInterface { + use EntityChangesDetectionTrait { + getFieldsToSkipFromTranslationChangesCheck as traitGetFieldsToSkipFromTranslationChangesCheck; + } + /** * The plain data values of the contained fields. * @@ -156,6 +160,22 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C */ protected $loadedRevisionId; + /** + * The revision translation affected entity key. + * + * @var string + */ + protected $revisionTranslationAffectedKey; + + /** + * Whether the revision translation affected flag has been enforced. + * + * An array, keyed by the translation language code. + * + * @var bool[] + */ + protected $enforceRevisionTranslationAffected = []; + /** * {@inheritdoc} */ @@ -164,6 +184,7 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C $this->entityKeys['bundle'] = $bundle ? $bundle : $this->entityTypeId; $this->langcodeKey = $this->getEntityType()->getKey('langcode'); $this->defaultLangcodeKey = $this->getEntityType()->getKey('default_langcode'); + $this->revisionTranslationAffectedKey = $this->getEntityType()->getKey('revision_translation_affected'); foreach ($values as $key => $value) { // If the key matches an existing property set the value to the property @@ -269,15 +290,11 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C // When saving a new revision, set any existing revision ID to NULL so as // to ensure that a new revision will actually be created. $this->set($this->getEntityType()->getKey('revision'), NULL); - - // Make sure that the flag tracking which translations are affected by the - // current revision is reset. - foreach ($this->translations as $langcode => $data) { - // But skip removed translations. - if ($this->hasTranslation($langcode)) { - $this->getTranslation($langcode)->setRevisionTranslationAffected(NULL); - } - } + } + elseif (!$value && $this->newRevision) { + // If ::setNewRevision(FALSE) is called after ::setNewRevision(TRUE) we + // have to restore the loaded revision ID. + $this->set($this->getEntityType()->getKey('revision'), $this->getLoadedRevisionId()); } $this->newRevision = $value; @@ -318,25 +335,73 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C return $this->isNew() || $return; } + /** + * {@inheritdoc} + */ + public function wasDefaultRevision() { + /** @var \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type */ + $entity_type = $this->getEntityType(); + if (!$entity_type->isRevisionable()) { + return TRUE; + } + + $revision_default_key = $entity_type->getRevisionMetadataKey('revision_default'); + $value = $this->isNew() || $this->get($revision_default_key)->value; + return $value; + } + + /** + * {@inheritdoc} + */ + public function isLatestRevision() { + /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */ + $storage = $this->entityTypeManager()->getStorage($this->getEntityTypeId()); + + return $this->getLoadedRevisionId() == $storage->getLatestRevisionId($this->id()); + } + + /** + * {@inheritdoc} + */ + public function isLatestTranslationAffectedRevision() { + /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */ + $storage = $this->entityTypeManager()->getStorage($this->getEntityTypeId()); + + return $this->getLoadedRevisionId() == $storage->getLatestTranslationAffectedRevisionId($this->id(), $this->language()->getId()); + } + /** * {@inheritdoc} */ public function isRevisionTranslationAffected() { - $field_name = $this->getEntityType()->getKey('revision_translation_affected'); - return $this->hasField($field_name) ? $this->get($field_name)->value : TRUE; + return $this->hasField($this->revisionTranslationAffectedKey) ? $this->get($this->revisionTranslationAffectedKey)->value : TRUE; } /** * {@inheritdoc} */ public function setRevisionTranslationAffected($affected) { - $field_name = $this->getEntityType()->getKey('revision_translation_affected'); - if ($this->hasField($field_name)) { - $this->set($field_name, $affected); + if ($this->hasField($this->revisionTranslationAffectedKey)) { + $this->set($this->revisionTranslationAffectedKey, $affected); } return $this; } + /** + * {@inheritdoc} + */ + public function isRevisionTranslationAffectedEnforced() { + return !empty($this->enforceRevisionTranslationAffected[$this->activeLangcode]); + } + + /** + * {@inheritdoc} + */ + public function setRevisionTranslationAffectedEnforced($enforced) { + $this->enforceRevisionTranslationAffected[$this->activeLangcode] = $enforced; + return $this; + } + /** * {@inheritdoc} */ @@ -355,8 +420,8 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C * {@inheritdoc} */ public function isTranslatable() { - // Check that the bundle is translatable, the entity has a language defined - // and if we have more than one language on the site. + // Check the bundle is translatable, the entity has a language defined, and + // the site has more than one language. $bundles = $this->entityManager()->getBundleInfo($this->entityTypeId); return !empty($bundles[$this->bundle()]['translatable']) && !$this->getUntranslated()->language()->isLocked() && $this->languageManager()->isMultilingual(); } @@ -401,6 +466,12 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C } } $this->translations = array_diff_key($this->translations, $removed); + + // Reset the new revision flag. + $this->newRevision = FALSE; + + // Reset the enforcement of the revision translation affected flag. + $this->enforceRevisionTranslationAffected = []; } /** @@ -716,7 +787,7 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C // If the revision identifier field is being populated with the original // value, we need to make sure the "new revision" flag is reset // accordingly. - if ($key === 'revision' && $this->getRevisionId() == $this->getLoadedRevisionId()) { + if ($key === 'revision' && $this->getRevisionId() == $this->getLoadedRevisionId() && !$this->isNew()) { $this->newRevision = FALSE; } } @@ -754,6 +825,12 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C throw new \LogicException($message); } break; + + case $this->revisionTranslationAffectedKey: + // If the revision translation affected flag is being set then enforce + // its value. + $this->setRevisionTranslationAffectedEnforced(TRUE); + break; } } @@ -837,6 +914,7 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C $translation->typedData = NULL; $translation->loadedRevisionId = &$this->loadedRevisionId; $translation->isDefaultRevision = &$this->isDefaultRevision; + $translation->enforceRevisionTranslationAffected = &$this->enforceRevisionTranslationAffected; return $translation; } @@ -1049,7 +1127,9 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C $duplicate = clone $this; $entity_type = $this->getEntityType(); - $duplicate->{$entity_type->getKey('id')}->value = NULL; + if ($entity_type->hasKey('id')) { + $duplicate->{$entity_type->getKey('id')}->value = NULL; + } $duplicate->enforceIsNew(); // Check if the entity type supports UUIDs and generate a new one if so. @@ -1104,7 +1184,8 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C // Ensure that the following properties are actually cloned by // overwriting the original references with ones pointing to copies of // them: enforceIsNew, newRevision, loadedRevisionId, fields, entityKeys, - // translatableEntityKeys, values and isDefaultRevision. + // translatableEntityKeys, values, isDefaultRevision and + // enforceRevisionTranslationAffected. $enforce_is_new = $this->enforceIsNew; $this->enforceIsNew = &$enforce_is_new; @@ -1129,6 +1210,9 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C $default_revision = $this->isDefaultRevision; $this->isDefaultRevision = &$default_revision; + $is_revision_translation_affected_enforced = $this->enforceRevisionTranslationAffected; + $this->enforceRevisionTranslationAffected = &$is_revision_translation_affected_enforced; + foreach ($this->fields as $name => $fields_by_langcode) { $this->fields[$name] = []; // Untranslatable fields may have multiple references for the same field @@ -1293,17 +1377,7 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C * An array of field names. */ protected function getFieldsToSkipFromTranslationChangesCheck() { - /** @var \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type */ - $entity_type = $this->getEntityType(); - // A list of known revision metadata fields which should be skipped from - // the comparision. - $fields = [ - $entity_type->getKey('revision'), - 'revision_translation_affected', - ]; - $fields = array_merge($fields, array_values($entity_type->getRevisionMetadataKeys())); - - return $fields; + return $this->traitGetFieldsToSkipFromTranslationChangesCheck($this); } /** @@ -1343,10 +1417,15 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C // The list of fields to skip from the comparision. $skip_fields = $this->getFieldsToSkipFromTranslationChangesCheck(); + // We also check untranslatable fields, so that a change to those will mark + // all translations as affected, unless they are configured to only affect + // the default translation. + $skip_untranslatable_fields = !$this->isDefaultTranslation() && $this->isDefaultTranslationAffectedOnly(); + foreach ($this->getFieldDefinitions() as $field_name => $definition) { // @todo Avoid special-casing the following fields. See // https://www.drupal.org/node/2329253. - if (in_array($field_name, $skip_fields, TRUE)) { + if (in_array($field_name, $skip_fields, TRUE) || ($skip_untranslatable_fields && !$definition->isTranslatable())) { continue; } $field = $this->get($field_name); @@ -1367,4 +1446,14 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C return FALSE; } + /** + * {@inheritdoc} + */ + public function isDefaultTranslationAffectedOnly() { + $bundle_name = $this->bundle(); + $bundle_info = \Drupal::service('entity_type.bundle.info') + ->getBundleInfo($this->getEntityTypeId()); + return !empty($bundle_info[$bundle_name]['untranslatable_fields.default_translation_affected']); + } + }