comparison core/modules/content_translation/src/ContentTranslationHandler.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 4c8ae668cc8c
children c2387f117808
comparison
equal deleted inserted replaced
13:5fb285c0d0e3 14:1fec387a4317
3 namespace Drupal\content_translation; 3 namespace Drupal\content_translation;
4 4
5 use Drupal\Core\Access\AccessResult; 5 use Drupal\Core\Access\AccessResult;
6 use Drupal\Core\DependencyInjection\DependencySerializationTrait; 6 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
7 use Drupal\Core\Entity\EntityChangedInterface; 7 use Drupal\Core\Entity\EntityChangedInterface;
8 use Drupal\Core\Entity\EntityChangesDetectionTrait;
8 use Drupal\Core\Entity\EntityHandlerInterface; 9 use Drupal\Core\Entity\EntityHandlerInterface;
9 use Drupal\Core\Entity\EntityInterface; 10 use Drupal\Core\Entity\EntityInterface;
10 use Drupal\Core\Entity\EntityManagerInterface; 11 use Drupal\Core\Entity\EntityManagerInterface;
11 use Drupal\Core\Entity\EntityTypeInterface; 12 use Drupal\Core\Entity\EntityTypeInterface;
12 use Drupal\Core\Field\BaseFieldDefinition; 13 use Drupal\Core\Field\BaseFieldDefinition;
13 use Drupal\Core\Form\FormStateInterface; 14 use Drupal\Core\Form\FormStateInterface;
14 use Drupal\Core\Language\LanguageInterface; 15 use Drupal\Core\Language\LanguageInterface;
15 use Drupal\Core\Language\LanguageManagerInterface; 16 use Drupal\Core\Language\LanguageManagerInterface;
17 use Drupal\Core\Messenger\MessengerInterface;
16 use Drupal\Core\Render\Element; 18 use Drupal\Core\Render\Element;
17 use Drupal\Core\Session\AccountInterface; 19 use Drupal\Core\Session\AccountInterface;
20 use Drupal\Core\StringTranslation\StringTranslationTrait;
18 use Drupal\user\Entity\User; 21 use Drupal\user\Entity\User;
19 use Drupal\user\EntityOwnerInterface; 22 use Drupal\user\EntityOwnerInterface;
20 use Symfony\Component\DependencyInjection\ContainerInterface; 23 use Symfony\Component\DependencyInjection\ContainerInterface;
21 24
22 /** 25 /**
23 * Base class for content translation handlers. 26 * Base class for content translation handlers.
24 * 27 *
25 * @ingroup entity_api 28 * @ingroup entity_api
26 */ 29 */
27 class ContentTranslationHandler implements ContentTranslationHandlerInterface, EntityHandlerInterface { 30 class ContentTranslationHandler implements ContentTranslationHandlerInterface, EntityHandlerInterface {
31
32 use EntityChangesDetectionTrait;
28 use DependencySerializationTrait; 33 use DependencySerializationTrait;
34 use StringTranslationTrait;
29 35
30 /** 36 /**
31 * The type of the entity being translated. 37 * The type of the entity being translated.
32 * 38 *
33 * @var string 39 * @var string
52 * The content translation manager. 58 * The content translation manager.
53 * 59 *
54 * @var \Drupal\content_translation\ContentTranslationManagerInterface 60 * @var \Drupal\content_translation\ContentTranslationManagerInterface
55 */ 61 */
56 protected $manager; 62 protected $manager;
63
64 /**
65 * The entity type manager.
66 *
67 * @var \Drupal\Core\Entity\EntityTypeManagerInterface
68 */
69 protected $entityTypeManager;
57 70
58 /** 71 /**
59 * The current user. 72 * The current user.
60 * 73 *
61 * @var \Drupal\Core\Session\AccountInterface 74 * @var \Drupal\Core\Session\AccountInterface
67 * by field name. 80 * by field name.
68 * 81 *
69 * @var \Drupal\Core\Field\FieldStorageDefinitionInterface[] 82 * @var \Drupal\Core\Field\FieldStorageDefinitionInterface[]
70 */ 83 */
71 protected $fieldStorageDefinitions; 84 protected $fieldStorageDefinitions;
85
86 /**
87 * The messenger service.
88 *
89 * @var \Drupal\Core\Messenger\MessengerInterface
90 */
91 protected $messenger;
72 92
73 /** 93 /**
74 * Initializes an instance of the content translation controller. 94 * Initializes an instance of the content translation controller.
75 * 95 *
76 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type 96 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
81 * The content translation manager service. 101 * The content translation manager service.
82 * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager 102 * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
83 * The entity manager. 103 * The entity manager.
84 * @param \Drupal\Core\Session\AccountInterface $current_user 104 * @param \Drupal\Core\Session\AccountInterface $current_user
85 * The current user. 105 * The current user.
86 */ 106 * @param \Drupal\Core\Messenger\MessengerInterface $messenger
87 public function __construct(EntityTypeInterface $entity_type, LanguageManagerInterface $language_manager, ContentTranslationManagerInterface $manager, EntityManagerInterface $entity_manager, AccountInterface $current_user) { 107 * The messenger service.
108 */
109 public function __construct(EntityTypeInterface $entity_type, LanguageManagerInterface $language_manager, ContentTranslationManagerInterface $manager, EntityManagerInterface $entity_manager, AccountInterface $current_user, MessengerInterface $messenger) {
88 $this->entityTypeId = $entity_type->id(); 110 $this->entityTypeId = $entity_type->id();
89 $this->entityType = $entity_type; 111 $this->entityType = $entity_type;
90 $this->languageManager = $language_manager; 112 $this->languageManager = $language_manager;
91 $this->manager = $manager; 113 $this->manager = $manager;
114 $this->entityTypeManager = $entity_manager;
92 $this->currentUser = $current_user; 115 $this->currentUser = $current_user;
93 $this->fieldStorageDefinitions = $entity_manager->getLastInstalledFieldStorageDefinitions($this->entityTypeId); 116 $this->fieldStorageDefinitions = $entity_manager->getLastInstalledFieldStorageDefinitions($this->entityTypeId);
117 $this->messenger = $messenger;
94 } 118 }
95 119
96 /** 120 /**
97 * {@inheritdoc} 121 * {@inheritdoc}
98 */ 122 */
100 return new static( 124 return new static(
101 $entity_type, 125 $entity_type,
102 $container->get('language_manager'), 126 $container->get('language_manager'),
103 $container->get('content_translation.manager'), 127 $container->get('content_translation.manager'),
104 $container->get('entity.manager'), 128 $container->get('entity.manager'),
105 $container->get('current_user') 129 $container->get('current_user'),
130 $container->get('messenger')
106 ); 131 );
107 } 132 }
108 133
109 /** 134 /**
110 * {@inheritdoc} 135 * {@inheritdoc}
267 292
268 /** 293 /**
269 * {@inheritdoc} 294 * {@inheritdoc}
270 */ 295 */
271 public function entityFormAlter(array &$form, FormStateInterface $form_state, EntityInterface $entity) { 296 public function entityFormAlter(array &$form, FormStateInterface $form_state, EntityInterface $entity) {
297 /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
298
272 $form_object = $form_state->getFormObject(); 299 $form_object = $form_state->getFormObject();
273 $form_langcode = $form_object->getFormLangcode($form_state); 300 $form_langcode = $form_object->getFormLangcode($form_state);
274 $entity_langcode = $entity->getUntranslated()->language()->getId(); 301 $entity_langcode = $entity->getUntranslated()->language()->getId();
275 $source_langcode = $this->getSourceLangcode($form_state); 302 $source_langcode = $this->getSourceLangcode($form_state);
276 303
361 if (isset($form['actions'][$key]['weight'])) { 388 if (isset($form['actions'][$key]['weight'])) {
362 $weight = $form['actions'][$key]['weight']; 389 $weight = $form['actions'][$key]['weight'];
363 break; 390 break;
364 } 391 }
365 } 392 }
366 $access = $this->getTranslationAccess($entity, 'delete')->isAllowed() || ($entity->access('delete') && $this->entityType->hasLinkTemplate('delete-form')); 393 /** @var \Drupal\Core\Access\AccessResultInterface $delete_access */
394 $delete_access = \Drupal::service('content_translation.delete_access')->checkAccess($entity);
395 $access = $delete_access->isAllowed() && (
396 $this->getTranslationAccess($entity, 'delete')->isAllowed() ||
397 ($entity->access('delete') && $this->entityType->hasLinkTemplate('delete-form'))
398 );
367 $form['actions']['delete_translation'] = [ 399 $form['actions']['delete_translation'] = [
368 '#type' => 'submit', 400 '#type' => 'submit',
369 '#value' => t('Delete translation'), 401 '#value' => t('Delete translation'),
370 '#weight' => $weight, 402 '#weight' => $weight,
371 '#submit' => [[$this, 'entityFormDeleteTranslation']], 403 '#submit' => [[$this, 'entityFormDeleteTranslation']],
424 '#description' => $description, 456 '#description' => $description,
425 '#disabled' => !$enabled, 457 '#disabled' => !$enabled,
426 ]; 458 ];
427 459
428 $translate = !$new_translation && $metadata->isOutdated(); 460 $translate = !$new_translation && $metadata->isOutdated();
429 if (!$translate) { 461 $outdated_access = !ContentTranslationManager::isPendingRevisionSupportEnabled($entity->getEntityTypeId(), $entity->bundle());
462 if (!$outdated_access) {
463 $form['content_translation']['outdated'] = [
464 '#markup' => $this->t('Translations cannot be flagged as outdated when content is moderated.'),
465 ];
466 }
467 elseif (!$translate) {
430 $form['content_translation']['retranslate'] = [ 468 $form['content_translation']['retranslate'] = [
431 '#type' => 'checkbox', 469 '#type' => 'checkbox',
432 '#title' => t('Flag other translations as outdated'), 470 '#title' => t('Flag other translations as outdated'),
433 '#default_value' => FALSE, 471 '#default_value' => FALSE,
434 '#description' => t('If you made a significant change, which means the other translations should be updated, you can flag all translations of this content as outdated. This will not change any other property of them, like whether they are published or not.'), 472 '#description' => t('If you made a significant change, which means the other translations should be updated, you can flag all translations of this content as outdated. This will not change any other property of them, like whether they are published or not.'),
473 '#access' => $outdated_access,
435 ]; 474 ];
436 } 475 }
437 else { 476 else {
438 $form['content_translation']['outdated'] = [ 477 $form['content_translation']['outdated'] = [
439 '#type' => 'checkbox', 478 '#type' => 'checkbox',
440 '#title' => t('This translation needs to be updated'), 479 '#title' => t('This translation needs to be updated'),
441 '#default_value' => $translate, 480 '#default_value' => $translate,
442 '#description' => t('When this option is checked, this translation needs to be updated. Uncheck when the translation is up to date again.'), 481 '#description' => t('When this option is checked, this translation needs to be updated. Uncheck when the translation is up to date again.'),
482 '#access' => $outdated_access,
443 ]; 483 ];
444 $form['content_translation']['#open'] = TRUE; 484 $form['content_translation']['#open'] = TRUE;
445 } 485 }
446 486
447 // Default to the anonymous user. 487 // Default to the anonymous user.
510 // multilingual value. 550 // multilingual value.
511 if (!isset($ignored_types)) { 551 if (!isset($ignored_types)) {
512 $ignored_types = array_flip(['actions', 'value', 'hidden', 'vertical_tabs', 'token', 'details']); 552 $ignored_types = array_flip(['actions', 'value', 'hidden', 'vertical_tabs', 'token', 'details']);
513 } 553 }
514 554
555 /** @var \Drupal\Core\Entity\ContentEntityForm $form_object */
556 $form_object = $form_state->getFormObject();
557 /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
558 $entity = $form_object->getEntity();
559 $display_translatability_clue = !$entity->isDefaultTranslationAffectedOnly();
560 $hide_untranslatable_fields = $entity->isDefaultTranslationAffectedOnly() && !$entity->isDefaultTranslation();
561 $translation_form = $form_state->get(['content_translation', 'translation_form']);
562 $display_warning = FALSE;
563
564 // We use field definitions to identify untranslatable field widgets to be
565 // hidden. Fields that are not involved in translation changes checks should
566 // not be affected by this logic (the "revision_log" field, for instance).
567 $field_definitions = array_diff_key($entity->getFieldDefinitions(), array_flip($this->getFieldsToSkipFromTranslationChangesCheck($entity)));
568
515 foreach (Element::children($element) as $key) { 569 foreach (Element::children($element) as $key) {
516 if (!isset($element[$key]['#type'])) { 570 if (!isset($element[$key]['#type'])) {
517 $this->entityFormSharedElements($element[$key], $form_state, $form); 571 $this->entityFormSharedElements($element[$key], $form_state, $form);
518 } 572 }
519 else { 573 else {
522 continue; 576 continue;
523 } 577 }
524 // Elements are considered to be non multilingual by default. 578 // Elements are considered to be non multilingual by default.
525 if (empty($element[$key]['#multilingual'])) { 579 if (empty($element[$key]['#multilingual'])) {
526 // If we are displaying a multilingual entity form we need to provide 580 // If we are displaying a multilingual entity form we need to provide
527 // translatability clues, otherwise the shared form elements should be 581 // translatability clues, otherwise the non-multilingual form elements
528 // hidden. 582 // should be hidden.
529 if (!$form_state->get(['content_translation', 'translation_form'])) { 583 if (!$translation_form) {
530 $this->addTranslatabilityClue($element[$key]); 584 if ($display_translatability_clue) {
585 $this->addTranslatabilityClue($element[$key]);
586 }
587 // Hide widgets for untranslatable fields.
588 if ($hide_untranslatable_fields && isset($field_definitions[$key])) {
589 $element[$key]['#access'] = FALSE;
590 $display_warning = TRUE;
591 }
531 } 592 }
532 else { 593 else {
533 $element[$key]['#access'] = FALSE; 594 $element[$key]['#access'] = FALSE;
534 } 595 }
535 } 596 }
536 } 597 }
598 }
599
600 if ($display_warning && !$form_state->isSubmitted() && !$form_state->isRebuilding()) {
601 $url = $entity->getUntranslated()->toUrl('edit-form')->toString();
602 $this->messenger->addWarning($this->t('Fields that apply to all languages are hidden to avoid conflicting changes. <a href=":url">Edit them on the original language form</a>.', [':url' => $url]));
537 } 603 }
538 604
539 return $element; 605 return $element;
540 } 606 }
541 607
641 707
642 // ContentEntityForm::submit will update the changed timestamp on submit 708 // ContentEntityForm::submit will update the changed timestamp on submit
643 // after the entity has been validated, so that it does not break the 709 // after the entity has been validated, so that it does not break the
644 // EntityChanged constraint validator. The content translation metadata 710 // EntityChanged constraint validator. The content translation metadata
645 // field for the changed timestamp does not have such a constraint defined 711 // field for the changed timestamp does not have such a constraint defined
646 // at the moment, but it is correct to update it's value in a submission 712 // at the moment, but it is correct to update its value in a submission
647 // handler as well and have the same logic like in the Form API. 713 // handler as well and have the same logic like in the Form API.
648 if ($entity->hasField('content_translation_changed')) { 714 if ($entity->hasField('content_translation_changed')) {
649 $metadata = $this->manager->getTranslationMetadata($entity); 715 $metadata = $this->manager->getTranslationMetadata($entity);
650 $metadata->setChangedTime(REQUEST_TIME); 716 $metadata->setChangedTime(REQUEST_TIME);
651 } 717 }