diff --git a/core/modules/content_moderation/content_moderation.module b/core/modules/content_moderation/content_moderation.module
index 7345e93..84f32b0 100644
--- a/core/modules/content_moderation/content_moderation.module
+++ b/core/modules/content_moderation/content_moderation.module
@@ -14,12 +14,12 @@
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityPublishedInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\workflows\WorkflowInterface;
-use Drupal\node\NodeInterface;
use Drupal\node\Plugin\Action\PublishNode;
use Drupal\node\Plugin\Action\UnpublishNode;
use Drupal\workflows\Entity\Workflow;
@@ -155,36 +155,36 @@ function content_moderation_entity_view(array &$build, EntityInterface $entity,
}
/**
- * Implements hook_node_access().
+ * Implements hook_entity_access().
*
* Nodes in particular should be viewable if unpublished and the user has
* the appropriate permission. This permission is therefore effectively
* mandatory for any user that wants to moderate things.
*/
-function content_moderation_node_access(NodeInterface $node, $operation, AccountInterface $account) {
+function content_moderation_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
/** @var \Drupal\content_moderation\ModerationInformationInterface $moderation_info */
$moderation_info = Drupal::service('content_moderation.moderation_information');
$access_result = NULL;
- if ($operation === 'view') {
- $access_result = (!$node->isPublished())
+ if ($operation === 'view' && $entity instanceof EntityPublishedInterface) {
+ $access_result = (!$entity->isPublished())
? AccessResult::allowedIfHasPermission($account, 'view any unpublished content')
: AccessResult::neutral();
- $access_result->addCacheableDependency($node);
+ $access_result->addCacheableDependency($entity);
}
- elseif ($operation === 'update' && $moderation_info->isModeratedEntity($node) && $node->moderation_state) {
+ elseif ($operation === 'update' && $moderation_info->isModeratedEntity($entity) && $entity->moderation_state) {
/** @var \Drupal\content_moderation\StateTransitionValidation $transition_validation */
$transition_validation = \Drupal::service('content_moderation.state_transition_validation');
- $valid_transition_targets = $transition_validation->getValidTransitions($node, $account);
- $access_result = $valid_transition_targets ? AccessResult::neutral() : AccessResult::forbidden();
+ $permitted_transition_targets = $transition_validation->getPermittedTransitions($entity, $account);
+ $access_result = $permitted_transition_targets ? AccessResult::neutral() : AccessResult::forbidden();
- $access_result->addCacheableDependency($node);
+ $access_result->addCacheableDependency($entity);
$access_result->addCacheableDependency($account);
- $workflow = \Drupal::service('content_moderation.moderation_information')->getWorkflowForEntity($node);
+ $workflow = \Drupal::service('content_moderation.moderation_information')->getWorkflowForEntity($entity);
$access_result->addCacheableDependency($workflow);
- foreach ($valid_transition_targets as $valid_transition_target) {
+ foreach ($permitted_transition_targets as $valid_transition_target) {
$access_result->addCacheableDependency($valid_transition_target);
}
}
@@ -251,3 +251,12 @@ function content_moderation_workflow_insert(WorkflowInterface $entity) {
function content_moderation_workflow_update(WorkflowInterface $entity) {
content_moderation_workflow_insert($entity);
}
+
+/**
+ * Implements hook_preprocess().
+ */
+function content_moderation_preprocess(&$variables, $hook) {
+ \Drupal::service('class_resolver')
+ ->getInstanceFromDefinition(EntityTypeInfo::class)
+ ->preprocess($variables, $hook);
+}
diff --git a/core/modules/content_moderation/src/EntityTypeInfo.php b/core/modules/content_moderation/src/EntityTypeInfo.php
index f11e471..d673e13 100644
--- a/core/modules/content_moderation/src/EntityTypeInfo.php
+++ b/core/modules/content_moderation/src/EntityTypeInfo.php
@@ -14,6 +14,7 @@
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
@@ -25,6 +26,7 @@
use Drupal\content_moderation\Routing\EntityModerationRouteProvider;
use Drupal\content_moderation\Routing\EntityTypeModerationRouteProvider;
use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Manipulates entity type information.
@@ -65,6 +67,13 @@ class EntityTypeInfo implements ContainerInjectionInterface {
protected $currentUser;
/**
+ * The state transition validation service.
+ *
+ * @var \Drupal\content_moderation\StateTransitionValidationInterface
+ */
+ protected $validator;
+
+ /**
* A keyed array of custom moderation handlers for given entity types.
*
* Any entity not specified will use a common default.
@@ -90,12 +99,13 @@ class EntityTypeInfo implements ContainerInjectionInterface {
* @param \Drupal\Core\Session\AccountInterface $current_user
* Current user.
*/
- public function __construct(TranslationInterface $translation, ModerationInformationInterface $moderation_information, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $bundle_info, AccountInterface $current_user) {
+ public function __construct(TranslationInterface $translation, ModerationInformationInterface $moderation_information, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $bundle_info, AccountInterface $current_user, StateTransitionValidationInterface $validator) {
$this->stringTranslation = $translation;
$this->moderationInfo = $moderation_information;
$this->entityTypeManager = $entity_type_manager;
$this->bundleInfo = $bundle_info;
$this->currentUser = $current_user;
+ $this->validator = $validator;
}
/**
@@ -107,7 +117,8 @@ public static function create(ContainerInterface $container) {
$container->get('content_moderation.moderation_information'),
$container->get('entity_type.manager'),
$container->get('entity_type.bundle.info'),
- $container->get('current_user')
+ $container->get('current_user'),
+ $container->get('content_moderation.state_transition_validation')
);
}
@@ -353,12 +364,38 @@ public function formAlter(array &$form, FormStateInterface $form_state, $form_id
$this->entityTypeManager->getHandler($type->getBundleOf(), 'moderation')->enforceRevisionsBundleFormAlter($form, $form_state, $form_id);
}
}
- elseif ($form_object instanceof ContentEntityFormInterface) {
+ elseif ($form_object instanceof ContentEntityFormInterface && $form_object->getOperation() == 'edit') {
$entity = $form_object->getEntity();
if ($this->moderationInfo->isModeratedEntity($entity)) {
$this->entityTypeManager
->getHandler($entity->getEntityTypeId(), 'moderation')
->enforceRevisionsEntityFormAlter($form, $form_state, $form_id);
+
+ $invalid_transitions = array_diff_key($this->validator->getPermittedTransitions($entity, $this->currentUser), $this->validator->getValidTransitions($entity, $this->currentUser));
+ if ($invalid_transitions) {
+ $labels = array_map(function ($transition) { return $transition->label(); }, $invalid_transitions);
+ $invalid_transition_labels = implode(', ', $labels);
+ $latest_revision = $this->getTranslationAffectedRevision($this->moderationInfo->getLatestRevision($entity->getEntityTypeId(), $entity->id()));
+ $form['invalid_transitions'] = [
+ 'rule' => [
+ '#type' => 'item',
+ '#markup' => '
',
+ ],
+ 'label' => [
+ '#type' => 'item',
+ '#prefix' => '',
+ '#markup' => \Drupal::translation()->translate('It is not possible to %invalid_transition_labels this @entity_type_label.', ['%invalid_transition_labels' => $invalid_transition_labels, '@entity_type_label' => $entity->getEntityType()->getLabel()]),
+ '#suffix' => '',
+ ],
+ 'message' => [
+ '#type' => 'item',
+ '#markup' => \Drupal::translation()->translate('Publish or delete the latest revision to allow all workflow transitions.', ['@latest_revision_edit_url' => $latest_revision->toUrl('edit-form', ['language' => $latest_revision->language()])->toString(), '@latest_revision_delete_url' => $latest_revision->toUrl('delete-form', ['language' => $latest_revision->language()])->toString()]),
+ ],
+ '#weight' => 999,
+ '#no_valid_transitions' => empty($this->validator->getValidTransitions($entity, $this->currentUser)),
+ ];
+ }
+
// Submit handler to redirect to the latest version, if available.
$form['actions']['submit']['#submit'][] = [EntityTypeInfo::class, 'bundleFormRedirect'];
}
@@ -366,6 +403,35 @@ public function formAlter(array &$form, FormStateInterface $form_state, $form_id
}
/**
+ * @param array $variables
+ * @param string $hook
+ */
+ public function preprocess(array &$variables, $hook) {
+ if (strpos($hook, '_edit_form') && $variables['form']['invalid_transitions']['#no_valid_transitions']) {
+ $invalid_transitions = $variables['form']['invalid_transitions'];
+ unset($variables['form']);
+ $variables['form'] = $invalid_transitions;
+ }
+ }
+
+ /**
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ * @return \Drupal\Core\Entity\EntityInterface
+ */
+ protected function getTranslationAffectedRevision(EntityInterface $entity) {
+ if ($entity->isRevisionTranslationAffected()) {
+ return $entity;
+ }
+ /** @var \Drupal\Core\Language\LanguageInterface $language */
+ foreach ($entity->getTranslationLanguages() as $language) {
+ $translation = $entity->getTranslation($language->getId());
+ if ($translation->isRevisionTranslationAffected()) {
+ return $translation;
+ }
+ }
+ }
+
+ /**
* Redirect content entity edit forms on save, if there is a forward revision.
*
* When saving their changes, editors should see those changes displayed on
diff --git a/core/modules/content_moderation/src/ParamConverter/EntityRevisionConverter.php b/core/modules/content_moderation/src/ParamConverter/EntityRevisionConverter.php
index 94f10e9..c981013 100644
--- a/core/modules/content_moderation/src/ParamConverter/EntityRevisionConverter.php
+++ b/core/modules/content_moderation/src/ParamConverter/EntityRevisionConverter.php
@@ -98,9 +98,7 @@ public function convert($value, $definition, $name, array $defaults) {
$latest_revision = $this->entityManager->getTranslationFromContext($latest_revision, NULL, ['operation' => 'entity_upcast']);
}
- if ($latest_revision->isRevisionTranslationAffected()) {
- $entity = $latest_revision;
- }
+ $entity = $latest_revision;
}
return $entity;
diff --git a/core/modules/content_moderation/src/StateTransitionValidation.php b/core/modules/content_moderation/src/StateTransitionValidation.php
index c4e26c2..f2f5df3 100644
--- a/core/modules/content_moderation/src/StateTransitionValidation.php
+++ b/core/modules/content_moderation/src/StateTransitionValidation.php
@@ -39,10 +39,40 @@ public function __construct(ModerationInformationInterface $moderation_info) {
* {@inheritdoc}
*/
public function getValidTransitions(ContentEntityInterface $entity, AccountInterface $user) {
+ $permitted_transitions = $this->getPermittedTransitions($entity, $user);
+ // For entities with more than one translation and forward revisions we
+ // want to only allow specific transitions.
+ if (count($entity->getTranslationLanguages()) > 1 && $this->moderationInfo->hasForwardRevision($entity)) {
+ $permitted_transitions = array_filter($permitted_transitions, function(Transition $transition) use ($entity) {
+ // The entity needs to be the latest and translation affected, or be
+ // going from and to the same default revision state, or be going from
+ // and to the same publishing state.
+ return (
+ $this->moderationInfo->isLatestRevision($entity) && $entity->isRevisionTranslationAffected()
+ ) || ((
+ ($entity->isDefaultRevision() && $transition->to()
+ ->isDefaultRevisionState())
+ || (!$entity->isDefaultRevision() && !$transition->to()
+ ->isDefaultRevisionState())
+ ) && (
+ ($entity->isPublished() && $transition->to()->isPublishedState())
+ || (!$entity->isPublished() && !$transition->to()
+ ->isPublishedState())
+ ));
+ });
+ }
+
+ return $permitted_transitions;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPermittedTransitions(ContentEntityInterface $entity, AccountInterface $user) {
$workflow = $this->moderationInfo->getWorkflowForEntity($entity);
$current_state = $entity->moderation_state->value ? $workflow->getState($entity->moderation_state->value) : $workflow->getInitialState();
- return array_filter($current_state->getTransitions(), function(Transition $transition) use ($workflow, $user) {
+ return array_filter($current_state->getTransitions(), function(Transition $transition) use ($workflow, $user, $entity) {
return $user->hasPermission('use ' . $workflow->id() . ' transition ' . $transition->id());
});
}
diff --git a/core/modules/content_moderation/src/StateTransitionValidationInterface.php b/core/modules/content_moderation/src/StateTransitionValidationInterface.php
index 1acbf05..25dd77d 100644
--- a/core/modules/content_moderation/src/StateTransitionValidationInterface.php
+++ b/core/modules/content_moderation/src/StateTransitionValidationInterface.php
@@ -11,6 +11,21 @@
interface StateTransitionValidationInterface {
/**
+ * Gets a list of transitions that are both legal and valid for this user on
+ * this entity.
+ *
+ * @param \Drupal\Core\Entity\ContentEntityInterface $entity
+ * The entity to be transitioned.
+ * @param \Drupal\Core\Session\AccountInterface $user
+ * The account that wants to perform a transition.
+ *
+ * @return \Drupal\workflows\Transition[]
+ * The list of transitions that are both legal and valid for this user on
+ * this entity.
+ */
+ public function getValidTransitions(ContentEntityInterface $entity, AccountInterface $user);
+
+ /**
* Gets a list of transitions that are legal for this user on this entity.
*
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
@@ -21,6 +36,6 @@
* @return \Drupal\workflows\Transition[]
* The list of transitions that are legal for this user on this entity.
*/
- public function getValidTransitions(ContentEntityInterface $entity, AccountInterface $user);
+ public function getPermittedTransitions(ContentEntityInterface $entity, AccountInterface $user);
}
diff --git a/core/modules/content_moderation/src/Tests/ModerationFormTest.php b/core/modules/content_moderation/src/Tests/ModerationFormTest.php
index 16da4e4..74a5a5b 100644
--- a/core/modules/content_moderation/src/Tests/ModerationFormTest.php
+++ b/core/modules/content_moderation/src/Tests/ModerationFormTest.php
@@ -9,6 +9,19 @@
*/
class ModerationFormTest extends ModerationStateTestBase {
+
+ /**
+ * Modules to enable.
+ *
+ * @var array
+ */
+ public static $modules = [
+ 'node',
+ 'content_moderation',
+ 'locale',
+ 'content_translation',
+ ];
+
/**
* {@inheritdoc}
*/
@@ -103,4 +116,128 @@ public function testModerationForm() {
$this->assertResponse(403);
}
+ public function testContentTranslationNodeForm() {
+ $this->drupalLogin($this->rootUser);
+
+ // Add French language.
+ $edit = [
+ 'predefined_langcode' => 'fr',
+ ];
+ $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
+
+ // Enable content translation on articles.
+ $this->drupalGet('admin/config/regional/content-language');
+ $edit = [
+ 'entity_types[node]' => TRUE,
+ 'settings[node][moderated_content][translatable]' => TRUE,
+ 'settings[node][moderated_content][settings][language][language_alterable]' => TRUE,
+ ];
+ $this->drupalPostForm(NULL, $edit, t('Save configuration'));
+
+ // Adding languages requires a container rebuild in the test running
+ // environment so that multilingual services are used.
+ $this->rebuildContainer();
+
+ // Create new moderated content in draft.
+ $this->drupalPostForm('node/add/moderated_content', [
+ 'title[0][value]' => 'Some moderated content',
+ 'body[0][value]' => 'First version of the content.',
+ ], t('Save and Create New Draft'));
+
+ $node = $this->drupalGetNodeByTitle('Some moderated content');
+ $this->assertTrue($node->language(), 'en');
+ $edit_path = sprintf('node/%d/edit', $node->id());
+ $translate_path = sprintf('node/%d/translations/add/en/fr', $node->id());
+
+ // Add french translation.
+ $this->drupalGet($translate_path);
+ $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
+ $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
+ $this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]'));
+ $this->drupalPostForm(NULL, [
+ 'body[0][value]' => 'Second version of the content.',
+ ], t('Save and Publish (this translation)'));
+
+ // Add french forward revision.
+ $this->drupalGet('fr/' . $edit_path);
+ $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
+ $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
+ $this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]'));
+ $this->drupalPostForm(NULL, [
+ 'body[0][value]' => 'Third version of the content.',
+ ], t('Save and Create New Draft (this translation)'));
+
+ // Add another english revision.
+ $this->drupalGet($edit_path);
+ $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
+ $this->assertFalse($this->xpath('//input[@value="Save and Publish (this translation)"]'));
+ $this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]'));
+ $this->assertText('It is not possible to Publish this Content.');
+ $this->drupalPostForm(NULL, [
+ 'body[0][value]' => 'Forth version of the content.',
+ ], t('Save and Create New Draft (this translation)'));
+
+ // Publish the french forward revision
+ $this->drupalGet('fr/' . $edit_path);
+ $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
+ $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
+ $this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]'));
+ $this->drupalPostForm(NULL, [
+ 'body[0][value]' => 'Fifth version of the content.',
+ ], t('Save and Publish (this translation)'));
+
+ // Now we can publish the english.
+ $this->drupalGet($edit_path);
+ $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
+ $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
+ $this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]'));
+ $this->drupalPostForm(NULL, [
+ 'body[0][value]' => 'Sixth version of the content.',
+ ], t('Save and Publish (this translation)'));
+
+ // Make sure we're allowed to create a forward french revision.
+ $this->drupalGet('fr/' . $edit_path);
+ $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
+ $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
+ $this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]'));
+
+ // Add a english forward revision.
+ $this->drupalGet($edit_path);
+ $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
+ $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
+ $this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]'));
+ $this->drupalPostForm(NULL, [
+ 'body[0][value]' => 'Seventh version of the content.',
+ ], t('Save and Create New Draft (this translation)'));
+
+ // Make sure we're not allowed to create a forward french revision.
+ $this->drupalGet('fr/' . $edit_path);
+ $this->assertFalse($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
+ $this->assertFalse($this->xpath('//input[@value="Save and Publish (this translation)"]'));
+ $this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]'));
+ $this->assertText('It is not possible to Create New Draft, Publish, Archive this Content.');
+
+ // We should be able to publish the english forward revision.
+ $this->drupalGet($edit_path);
+ $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
+ $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
+ $this->assertFalse($this->xpath('//input[@value="Save and Archive (this translation)"]'));
+ $this->drupalPostForm(NULL, [
+ 'body[0][value]' => 'Eighth version of the content.',
+ ], t('Save and Publish (this translation)'));
+
+ // Make sure we're allowed to create a forward french revision.
+ $this->drupalGet('fr/' . $edit_path);
+ $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
+ $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
+ $this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]'));
+
+ // Make sure we're allowed to create a forward english revision.
+ $this->drupalGet($edit_path);
+ $this->assertTrue($this->xpath('//input[@value="Save and Create New Draft (this translation)"]'));
+ $this->assertTrue($this->xpath('//input[@value="Save and Publish (this translation)"]'));
+ $this->assertTrue($this->xpath('//input[@value="Save and Archive (this translation)"]'));
+
+ }
+
}
diff --git a/core/modules/content_moderation/tests/src/Functional/ModerationLocaleTest.php b/core/modules/content_moderation/tests/src/Functional/ModerationLocaleTest.php
index a9d95f0..7b50613 100644
--- a/core/modules/content_moderation/tests/src/Functional/ModerationLocaleTest.php
+++ b/core/modules/content_moderation/tests/src/Functional/ModerationLocaleTest.php
@@ -144,17 +144,12 @@ public function testTranslateModeratedContent() {
$this->assertTrue($french_node->isPublished());
$this->assertEqual($french_node->getTitle(), 'Translated node', 'The default revision of the published translation remains the same.');
- // Publish the draft.
- $edit = [
- 'new_state' => 'published',
- ];
- $this->drupalPostForm('fr/node/' . $english_node->id() . '/latest', $edit, t('Apply'));
- $this->assertText(t('The moderation state has been updated.'));
+ // Publish the French article before testing the archive transition.
+ $this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', [], t('Save and Publish (this translation)'));
+ $this->assertText(t('Article New draft of translated node has been updated.'));
$english_node = $this->drupalGetNodeByTitle('Another node', TRUE);
$french_node = $english_node->getTranslation('fr');
$this->assertEqual($french_node->moderation_state->value, 'published');
- $this->assertTrue($french_node->isPublished());
- $this->assertEqual($french_node->getTitle(), 'New draft of translated node', 'The draft has replaced the published revision.');
// Publish the English article before testing the archive transition.
$this->drupalPostForm('node/' . $english_node->id() . '/edit', [], t('Save and Publish (this translation)'));
@@ -173,43 +168,6 @@ public function testTranslateModeratedContent() {
$this->assertFalse($english_node->isPublished());
$this->assertEqual($french_node->moderation_state->value, 'archived');
$this->assertFalse($french_node->isPublished());
-
- // Create another article with its translation. This time publishing english
- // after creating a forward french revision.
- $edit = [
- 'title[0][value]' => 'An english node',
- ];
- $this->drupalPostForm('node/add/article', $edit, t('Save and Create New Draft'));
- $this->assertText(t('Article An english node has been created.'));
- $english_node = $this->drupalGetNodeByTitle('An english node');
- $this->assertFalse($english_node->isPublished());
-
- // Add a French translation.
- $this->drupalGet('node/' . $english_node->id() . '/translations');
- $this->clickLink(t('Add'));
- $edit = [
- 'title[0][value]' => 'A french node',
- ];
- $this->drupalPostForm(NULL, $edit, t('Save and Publish (this translation)'));
- $english_node = $this->drupalGetNodeByTitle('An english node', TRUE);
- $french_node = $english_node->getTranslation('fr');
- $this->assertTrue($french_node->isPublished());
- $this->assertFalse($english_node->isPublished());
-
- // Create a forward revision
- $this->drupalPostForm('fr/node/' . $english_node->id() . '/edit', [], t('Save and Create New Draft (this translation)'));
- $english_node = $this->drupalGetNodeByTitle('An english node', TRUE);
- $french_node = $english_node->getTranslation('fr');
- $this->assertTrue($french_node->isPublished());
- $this->assertFalse($english_node->isPublished());
-
- // Publish the english node and the default french node not the latest
- // french node should be used.
- $this->drupalPostForm('/node/' . $english_node->id() . '/edit', [], t('Save and Publish (this translation)'));
- $english_node = $this->drupalGetNodeByTitle('An english node', TRUE);
- $french_node = $english_node->getTranslation('fr');
- $this->assertTrue($french_node->isPublished());
- $this->assertTrue($english_node->isPublished());
}
}