Mercurial > hg > isophonics-drupal-site
comparison core/lib/Drupal/Core/Entity/ContentEntityBase.php @ 14:1fec387a4317
Update Drupal core to 8.5.2 via Composer
author | Chris Cannam |
---|---|
date | Mon, 23 Apr 2018 09:46:53 +0100 |
parents | 7a779792577d |
children | c2387f117808 |
comparison
equal
deleted
inserted
replaced
13:5fb285c0d0e3 | 14:1fec387a4317 |
---|---|
18 * | 18 * |
19 * @ingroup entity_api | 19 * @ingroup entity_api |
20 */ | 20 */ |
21 abstract class ContentEntityBase extends Entity implements \IteratorAggregate, ContentEntityInterface, TranslationStatusInterface { | 21 abstract class ContentEntityBase extends Entity implements \IteratorAggregate, ContentEntityInterface, TranslationStatusInterface { |
22 | 22 |
23 use EntityChangesDetectionTrait { | |
24 getFieldsToSkipFromTranslationChangesCheck as traitGetFieldsToSkipFromTranslationChangesCheck; | |
25 } | |
26 | |
23 /** | 27 /** |
24 * The plain data values of the contained fields. | 28 * The plain data values of the contained fields. |
25 * | 29 * |
26 * This always holds the original, unchanged values of the entity. The values | 30 * This always holds the original, unchanged values of the entity. The values |
27 * are keyed by language code, whereas LanguageInterface::LANGCODE_DEFAULT | 31 * are keyed by language code, whereas LanguageInterface::LANGCODE_DEFAULT |
153 * The loaded revision ID before the new revision was set. | 157 * The loaded revision ID before the new revision was set. |
154 * | 158 * |
155 * @var int | 159 * @var int |
156 */ | 160 */ |
157 protected $loadedRevisionId; | 161 protected $loadedRevisionId; |
162 | |
163 /** | |
164 * The revision translation affected entity key. | |
165 * | |
166 * @var string | |
167 */ | |
168 protected $revisionTranslationAffectedKey; | |
169 | |
170 /** | |
171 * Whether the revision translation affected flag has been enforced. | |
172 * | |
173 * An array, keyed by the translation language code. | |
174 * | |
175 * @var bool[] | |
176 */ | |
177 protected $enforceRevisionTranslationAffected = []; | |
158 | 178 |
159 /** | 179 /** |
160 * {@inheritdoc} | 180 * {@inheritdoc} |
161 */ | 181 */ |
162 public function __construct(array $values, $entity_type, $bundle = FALSE, $translations = []) { | 182 public function __construct(array $values, $entity_type, $bundle = FALSE, $translations = []) { |
163 $this->entityTypeId = $entity_type; | 183 $this->entityTypeId = $entity_type; |
164 $this->entityKeys['bundle'] = $bundle ? $bundle : $this->entityTypeId; | 184 $this->entityKeys['bundle'] = $bundle ? $bundle : $this->entityTypeId; |
165 $this->langcodeKey = $this->getEntityType()->getKey('langcode'); | 185 $this->langcodeKey = $this->getEntityType()->getKey('langcode'); |
166 $this->defaultLangcodeKey = $this->getEntityType()->getKey('default_langcode'); | 186 $this->defaultLangcodeKey = $this->getEntityType()->getKey('default_langcode'); |
187 $this->revisionTranslationAffectedKey = $this->getEntityType()->getKey('revision_translation_affected'); | |
167 | 188 |
168 foreach ($values as $key => $value) { | 189 foreach ($values as $key => $value) { |
169 // If the key matches an existing property set the value to the property | 190 // If the key matches an existing property set the value to the property |
170 // to set properties like isDefaultRevision. | 191 // to set properties like isDefaultRevision. |
171 // @todo: Should this be converted somehow? | 192 // @todo: Should this be converted somehow? |
267 | 288 |
268 if ($value && !$this->newRevision) { | 289 if ($value && !$this->newRevision) { |
269 // When saving a new revision, set any existing revision ID to NULL so as | 290 // When saving a new revision, set any existing revision ID to NULL so as |
270 // to ensure that a new revision will actually be created. | 291 // to ensure that a new revision will actually be created. |
271 $this->set($this->getEntityType()->getKey('revision'), NULL); | 292 $this->set($this->getEntityType()->getKey('revision'), NULL); |
272 | 293 } |
273 // Make sure that the flag tracking which translations are affected by the | 294 elseif (!$value && $this->newRevision) { |
274 // current revision is reset. | 295 // If ::setNewRevision(FALSE) is called after ::setNewRevision(TRUE) we |
275 foreach ($this->translations as $langcode => $data) { | 296 // have to restore the loaded revision ID. |
276 // But skip removed translations. | 297 $this->set($this->getEntityType()->getKey('revision'), $this->getLoadedRevisionId()); |
277 if ($this->hasTranslation($langcode)) { | |
278 $this->getTranslation($langcode)->setRevisionTranslationAffected(NULL); | |
279 } | |
280 } | |
281 } | 298 } |
282 | 299 |
283 $this->newRevision = $value; | 300 $this->newRevision = $value; |
284 } | 301 } |
285 | 302 |
319 } | 336 } |
320 | 337 |
321 /** | 338 /** |
322 * {@inheritdoc} | 339 * {@inheritdoc} |
323 */ | 340 */ |
341 public function wasDefaultRevision() { | |
342 /** @var \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type */ | |
343 $entity_type = $this->getEntityType(); | |
344 if (!$entity_type->isRevisionable()) { | |
345 return TRUE; | |
346 } | |
347 | |
348 $revision_default_key = $entity_type->getRevisionMetadataKey('revision_default'); | |
349 $value = $this->isNew() || $this->get($revision_default_key)->value; | |
350 return $value; | |
351 } | |
352 | |
353 /** | |
354 * {@inheritdoc} | |
355 */ | |
356 public function isLatestRevision() { | |
357 /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */ | |
358 $storage = $this->entityTypeManager()->getStorage($this->getEntityTypeId()); | |
359 | |
360 return $this->getLoadedRevisionId() == $storage->getLatestRevisionId($this->id()); | |
361 } | |
362 | |
363 /** | |
364 * {@inheritdoc} | |
365 */ | |
366 public function isLatestTranslationAffectedRevision() { | |
367 /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */ | |
368 $storage = $this->entityTypeManager()->getStorage($this->getEntityTypeId()); | |
369 | |
370 return $this->getLoadedRevisionId() == $storage->getLatestTranslationAffectedRevisionId($this->id(), $this->language()->getId()); | |
371 } | |
372 | |
373 /** | |
374 * {@inheritdoc} | |
375 */ | |
324 public function isRevisionTranslationAffected() { | 376 public function isRevisionTranslationAffected() { |
325 $field_name = $this->getEntityType()->getKey('revision_translation_affected'); | 377 return $this->hasField($this->revisionTranslationAffectedKey) ? $this->get($this->revisionTranslationAffectedKey)->value : TRUE; |
326 return $this->hasField($field_name) ? $this->get($field_name)->value : TRUE; | |
327 } | 378 } |
328 | 379 |
329 /** | 380 /** |
330 * {@inheritdoc} | 381 * {@inheritdoc} |
331 */ | 382 */ |
332 public function setRevisionTranslationAffected($affected) { | 383 public function setRevisionTranslationAffected($affected) { |
333 $field_name = $this->getEntityType()->getKey('revision_translation_affected'); | 384 if ($this->hasField($this->revisionTranslationAffectedKey)) { |
334 if ($this->hasField($field_name)) { | 385 $this->set($this->revisionTranslationAffectedKey, $affected); |
335 $this->set($field_name, $affected); | 386 } |
336 } | 387 return $this; |
388 } | |
389 | |
390 /** | |
391 * {@inheritdoc} | |
392 */ | |
393 public function isRevisionTranslationAffectedEnforced() { | |
394 return !empty($this->enforceRevisionTranslationAffected[$this->activeLangcode]); | |
395 } | |
396 | |
397 /** | |
398 * {@inheritdoc} | |
399 */ | |
400 public function setRevisionTranslationAffectedEnforced($enforced) { | |
401 $this->enforceRevisionTranslationAffected[$this->activeLangcode] = $enforced; | |
337 return $this; | 402 return $this; |
338 } | 403 } |
339 | 404 |
340 /** | 405 /** |
341 * {@inheritdoc} | 406 * {@inheritdoc} |
353 | 418 |
354 /** | 419 /** |
355 * {@inheritdoc} | 420 * {@inheritdoc} |
356 */ | 421 */ |
357 public function isTranslatable() { | 422 public function isTranslatable() { |
358 // Check that the bundle is translatable, the entity has a language defined | 423 // Check the bundle is translatable, the entity has a language defined, and |
359 // and if we have more than one language on the site. | 424 // the site has more than one language. |
360 $bundles = $this->entityManager()->getBundleInfo($this->entityTypeId); | 425 $bundles = $this->entityManager()->getBundleInfo($this->entityTypeId); |
361 return !empty($bundles[$this->bundle()]['translatable']) && !$this->getUntranslated()->language()->isLocked() && $this->languageManager()->isMultilingual(); | 426 return !empty($bundles[$this->bundle()]['translatable']) && !$this->getUntranslated()->language()->isLocked() && $this->languageManager()->isMultilingual(); |
362 } | 427 } |
363 | 428 |
364 /** | 429 /** |
399 else { | 464 else { |
400 $data['status'] = static::TRANSLATION_EXISTING; | 465 $data['status'] = static::TRANSLATION_EXISTING; |
401 } | 466 } |
402 } | 467 } |
403 $this->translations = array_diff_key($this->translations, $removed); | 468 $this->translations = array_diff_key($this->translations, $removed); |
469 | |
470 // Reset the new revision flag. | |
471 $this->newRevision = FALSE; | |
472 | |
473 // Reset the enforcement of the revision translation affected flag. | |
474 $this->enforceRevisionTranslationAffected = []; | |
404 } | 475 } |
405 | 476 |
406 /** | 477 /** |
407 * {@inheritdoc} | 478 * {@inheritdoc} |
408 */ | 479 */ |
714 unset($this->translatableEntityKeys[$key][$this->activeLangcode]); | 785 unset($this->translatableEntityKeys[$key][$this->activeLangcode]); |
715 } | 786 } |
716 // If the revision identifier field is being populated with the original | 787 // If the revision identifier field is being populated with the original |
717 // value, we need to make sure the "new revision" flag is reset | 788 // value, we need to make sure the "new revision" flag is reset |
718 // accordingly. | 789 // accordingly. |
719 if ($key === 'revision' && $this->getRevisionId() == $this->getLoadedRevisionId()) { | 790 if ($key === 'revision' && $this->getRevisionId() == $this->getLoadedRevisionId() && !$this->isNew()) { |
720 $this->newRevision = FALSE; | 791 $this->newRevision = FALSE; |
721 } | 792 } |
722 } | 793 } |
723 } | 794 } |
724 | 795 |
751 if (isset($this->values[$this->defaultLangcodeKey]) && $this->get($this->defaultLangcodeKey)->value != $this->isDefaultTranslation()) { | 822 if (isset($this->values[$this->defaultLangcodeKey]) && $this->get($this->defaultLangcodeKey)->value != $this->isDefaultTranslation()) { |
752 $this->get($this->defaultLangcodeKey)->setValue($this->isDefaultTranslation(), FALSE); | 823 $this->get($this->defaultLangcodeKey)->setValue($this->isDefaultTranslation(), FALSE); |
753 $message = SafeMarkup::format('The default translation flag cannot be changed (@langcode).', ['@langcode' => $this->activeLangcode]); | 824 $message = SafeMarkup::format('The default translation flag cannot be changed (@langcode).', ['@langcode' => $this->activeLangcode]); |
754 throw new \LogicException($message); | 825 throw new \LogicException($message); |
755 } | 826 } |
827 break; | |
828 | |
829 case $this->revisionTranslationAffectedKey: | |
830 // If the revision translation affected flag is being set then enforce | |
831 // its value. | |
832 $this->setRevisionTranslationAffectedEnforced(TRUE); | |
756 break; | 833 break; |
757 } | 834 } |
758 } | 835 } |
759 | 836 |
760 /** | 837 /** |
835 $translation->translatableEntityKeys = &$this->translatableEntityKeys; | 912 $translation->translatableEntityKeys = &$this->translatableEntityKeys; |
836 $translation->translationInitialize = FALSE; | 913 $translation->translationInitialize = FALSE; |
837 $translation->typedData = NULL; | 914 $translation->typedData = NULL; |
838 $translation->loadedRevisionId = &$this->loadedRevisionId; | 915 $translation->loadedRevisionId = &$this->loadedRevisionId; |
839 $translation->isDefaultRevision = &$this->isDefaultRevision; | 916 $translation->isDefaultRevision = &$this->isDefaultRevision; |
917 $translation->enforceRevisionTranslationAffected = &$this->enforceRevisionTranslationAffected; | |
840 | 918 |
841 return $translation; | 919 return $translation; |
842 } | 920 } |
843 | 921 |
844 /** | 922 /** |
1047 throw new \InvalidArgumentException("The entity object refers to a removed translation ({$this->activeLangcode}) and cannot be manipulated."); | 1125 throw new \InvalidArgumentException("The entity object refers to a removed translation ({$this->activeLangcode}) and cannot be manipulated."); |
1048 } | 1126 } |
1049 | 1127 |
1050 $duplicate = clone $this; | 1128 $duplicate = clone $this; |
1051 $entity_type = $this->getEntityType(); | 1129 $entity_type = $this->getEntityType(); |
1052 $duplicate->{$entity_type->getKey('id')}->value = NULL; | 1130 if ($entity_type->hasKey('id')) { |
1131 $duplicate->{$entity_type->getKey('id')}->value = NULL; | |
1132 } | |
1053 $duplicate->enforceIsNew(); | 1133 $duplicate->enforceIsNew(); |
1054 | 1134 |
1055 // Check if the entity type supports UUIDs and generate a new one if so. | 1135 // Check if the entity type supports UUIDs and generate a new one if so. |
1056 if ($entity_type->hasKey('uuid')) { | 1136 if ($entity_type->hasKey('uuid')) { |
1057 $duplicate->{$entity_type->getKey('uuid')}->value = $this->uuidGenerator()->generate(); | 1137 $duplicate->{$entity_type->getKey('uuid')}->value = $this->uuidGenerator()->generate(); |
1102 $this->translations = &$translations; | 1182 $this->translations = &$translations; |
1103 | 1183 |
1104 // Ensure that the following properties are actually cloned by | 1184 // Ensure that the following properties are actually cloned by |
1105 // overwriting the original references with ones pointing to copies of | 1185 // overwriting the original references with ones pointing to copies of |
1106 // them: enforceIsNew, newRevision, loadedRevisionId, fields, entityKeys, | 1186 // them: enforceIsNew, newRevision, loadedRevisionId, fields, entityKeys, |
1107 // translatableEntityKeys, values and isDefaultRevision. | 1187 // translatableEntityKeys, values, isDefaultRevision and |
1188 // enforceRevisionTranslationAffected. | |
1108 $enforce_is_new = $this->enforceIsNew; | 1189 $enforce_is_new = $this->enforceIsNew; |
1109 $this->enforceIsNew = &$enforce_is_new; | 1190 $this->enforceIsNew = &$enforce_is_new; |
1110 | 1191 |
1111 $new_revision = $this->newRevision; | 1192 $new_revision = $this->newRevision; |
1112 $this->newRevision = &$new_revision; | 1193 $this->newRevision = &$new_revision; |
1126 $values = $this->values; | 1207 $values = $this->values; |
1127 $this->values = &$values; | 1208 $this->values = &$values; |
1128 | 1209 |
1129 $default_revision = $this->isDefaultRevision; | 1210 $default_revision = $this->isDefaultRevision; |
1130 $this->isDefaultRevision = &$default_revision; | 1211 $this->isDefaultRevision = &$default_revision; |
1212 | |
1213 $is_revision_translation_affected_enforced = $this->enforceRevisionTranslationAffected; | |
1214 $this->enforceRevisionTranslationAffected = &$is_revision_translation_affected_enforced; | |
1131 | 1215 |
1132 foreach ($this->fields as $name => $fields_by_langcode) { | 1216 foreach ($this->fields as $name => $fields_by_langcode) { |
1133 $this->fields[$name] = []; | 1217 $this->fields[$name] = []; |
1134 // Untranslatable fields may have multiple references for the same field | 1218 // Untranslatable fields may have multiple references for the same field |
1135 // object keyed by language. To avoid creating different field objects | 1219 // object keyed by language. To avoid creating different field objects |
1291 * | 1375 * |
1292 * @return array | 1376 * @return array |
1293 * An array of field names. | 1377 * An array of field names. |
1294 */ | 1378 */ |
1295 protected function getFieldsToSkipFromTranslationChangesCheck() { | 1379 protected function getFieldsToSkipFromTranslationChangesCheck() { |
1296 /** @var \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type */ | 1380 return $this->traitGetFieldsToSkipFromTranslationChangesCheck($this); |
1297 $entity_type = $this->getEntityType(); | |
1298 // A list of known revision metadata fields which should be skipped from | |
1299 // the comparision. | |
1300 $fields = [ | |
1301 $entity_type->getKey('revision'), | |
1302 'revision_translation_affected', | |
1303 ]; | |
1304 $fields = array_merge($fields, array_values($entity_type->getRevisionMetadataKeys())); | |
1305 | |
1306 return $fields; | |
1307 } | 1381 } |
1308 | 1382 |
1309 /** | 1383 /** |
1310 * {@inheritdoc} | 1384 * {@inheritdoc} |
1311 */ | 1385 */ |
1341 $translation = $original->getTranslation($this->activeLangcode); | 1415 $translation = $original->getTranslation($this->activeLangcode); |
1342 | 1416 |
1343 // The list of fields to skip from the comparision. | 1417 // The list of fields to skip from the comparision. |
1344 $skip_fields = $this->getFieldsToSkipFromTranslationChangesCheck(); | 1418 $skip_fields = $this->getFieldsToSkipFromTranslationChangesCheck(); |
1345 | 1419 |
1420 // We also check untranslatable fields, so that a change to those will mark | |
1421 // all translations as affected, unless they are configured to only affect | |
1422 // the default translation. | |
1423 $skip_untranslatable_fields = !$this->isDefaultTranslation() && $this->isDefaultTranslationAffectedOnly(); | |
1424 | |
1346 foreach ($this->getFieldDefinitions() as $field_name => $definition) { | 1425 foreach ($this->getFieldDefinitions() as $field_name => $definition) { |
1347 // @todo Avoid special-casing the following fields. See | 1426 // @todo Avoid special-casing the following fields. See |
1348 // https://www.drupal.org/node/2329253. | 1427 // https://www.drupal.org/node/2329253. |
1349 if (in_array($field_name, $skip_fields, TRUE)) { | 1428 if (in_array($field_name, $skip_fields, TRUE) || ($skip_untranslatable_fields && !$definition->isTranslatable())) { |
1350 continue; | 1429 continue; |
1351 } | 1430 } |
1352 $field = $this->get($field_name); | 1431 $field = $this->get($field_name); |
1353 // When saving entities in the user interface, the changed timestamp is | 1432 // When saving entities in the user interface, the changed timestamp is |
1354 // automatically incremented by ContentEntityForm::submitForm() even if | 1433 // automatically incremented by ContentEntityForm::submitForm() even if |
1365 } | 1444 } |
1366 | 1445 |
1367 return FALSE; | 1446 return FALSE; |
1368 } | 1447 } |
1369 | 1448 |
1449 /** | |
1450 * {@inheritdoc} | |
1451 */ | |
1452 public function isDefaultTranslationAffectedOnly() { | |
1453 $bundle_name = $this->bundle(); | |
1454 $bundle_info = \Drupal::service('entity_type.bundle.info') | |
1455 ->getBundleInfo($this->getEntityTypeId()); | |
1456 return !empty($bundle_info[$bundle_name]['untranslatable_fields.default_translation_affected']); | |
1457 } | |
1458 | |
1370 } | 1459 } |