Updated to Drupal 8.5. Core Media not yet in use.
[yaffs-website] / web / core / lib / Drupal / Core / Entity / ContentEntityBase.php
index 43db12fd796e59dab5d4d8ebc5004e395ef88931..6b999c6977f5f2a0252387b3f8fac7c535579ced 100644 (file)
@@ -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']);
+  }
+
 }