From 469003db9e16a42cd45dee9a5a4769f6821cd2c5 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Mon, 8 May 2017 11:50:29 +0100
Subject: [PATCH] Issue #2817835 by timmillwood, Sam152, alexpott: When
 enabling moderation apply a relative state

---
 .../src/EntityOperations.php                  |  2 +-
 .../FieldWidget/ModerationStateWidget.php     |  2 +-
 .../Field/ModerationStateFieldItemList.php    |  4 +-
 .../Plugin/WorkflowType/ContentModeration.php | 11 +++
 .../src/StateTransitionValidation.php         |  2 +-
 .../src/Kernel/ContentModerationStateTest.php |  3 +
 .../tests/src/Kernel/InitialStateTest.php     | 82 +++++++++++++++++++
 .../ModerationStateFieldItemListTest.php      |  4 +-
 .../modules/workflows/src/Entity/Workflow.php |  8 --
 .../workflows/src/Plugin/WorkflowTypeBase.php |  8 ++
 .../workflows/src/WorkflowInterface.php       |  8 --
 .../workflows/src/WorkflowTypeInterface.php   | 11 +++
 .../tests/src/Functional/WorkflowUiTest.php   |  4 +-
 .../workflows/tests/src/Unit/WorkflowTest.php | 19 -----
 14 files changed, 124 insertions(+), 44 deletions(-)
 create mode 100644 core/modules/content_moderation/tests/src/Kernel/InitialStateTest.php

diff --git a/core/modules/content_moderation/src/EntityOperations.php b/core/modules/content_moderation/src/EntityOperations.php
index 3e34d141ec93..3f66100581bd 100644
--- a/core/modules/content_moderation/src/EntityOperations.php
+++ b/core/modules/content_moderation/src/EntityOperations.php
@@ -158,7 +158,7 @@ protected function updateOrCreateFromEntity(EntityInterface $entity) {
     $workflow = $this->moderationInfo->getWorkflowForEntity($entity);
     /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
     if (!$moderation_state) {
-      $moderation_state = $workflow->getInitialState()->id();
+      $moderation_state = $workflow->getTypePlugin()->getInitialState($workflow, $entity)->id();
     }
 
     // @todo what if $entity->moderation_state is null at this point?
diff --git a/core/modules/content_moderation/src/Plugin/Field/FieldWidget/ModerationStateWidget.php b/core/modules/content_moderation/src/Plugin/Field/FieldWidget/ModerationStateWidget.php
index 970ac33a5dcc..ab5a5613609a 100644
--- a/core/modules/content_moderation/src/Plugin/Field/FieldWidget/ModerationStateWidget.php
+++ b/core/modules/content_moderation/src/Plugin/Field/FieldWidget/ModerationStateWidget.php
@@ -117,7 +117,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
     }
 
     $workflow = $this->moderationInformation->getWorkflowForEntity($entity);
-    $default = $items->get($delta)->value ? $workflow->getState($items->get($delta)->value) : $workflow->getInitialState();
+    $default = $items->get($delta)->value ? $workflow->getState($items->get($delta)->value) : $workflow->getTypePlugin()->getInitialState($workflow, $entity);
     if (!$default) {
       throw new \UnexpectedValueException(sprintf('The %s bundle has an invalid moderation state configuration, moderation states are enabled but no default is set.', $bundle_entity->label()));
     }
diff --git a/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php b/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php
index 0444644f9326..2d93f5a7c2a9 100644
--- a/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php
+++ b/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php
@@ -37,8 +37,8 @@ protected function getModerationStateId() {
     // It is possible that the bundle does not exist at this point. For example,
     // the node type form creates a fake Node entity to get default values.
     // @see \Drupal\node\NodeTypeForm::form()
-    $workflow = $moderation_info->getWorkflowForEntity($entity);
-    return $workflow ? $workflow->getInitialState()->id() : NULL;
+    $workflow = $moderation_info->getWorkFlowForEntity($entity);
+    return $workflow ? $workflow->getTypePlugin()->getInitialState($workflow, $entity)->id() : NULL;
   }
 
   /**
diff --git a/core/modules/content_moderation/src/Plugin/WorkflowType/ContentModeration.php b/core/modules/content_moderation/src/Plugin/WorkflowType/ContentModeration.php
index 31f1c18c682b..51605d5383d6 100644
--- a/core/modules/content_moderation/src/Plugin/WorkflowType/ContentModeration.php
+++ b/core/modules/content_moderation/src/Plugin/WorkflowType/ContentModeration.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Entity\EntityPublishedInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Session\AccountInterface;
@@ -289,4 +290,14 @@ public function getConfiguration() {
     return $configuration;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getInitialState(WorkflowInterface $workflow, $entity = NULL) {
+    if ($entity instanceof EntityPublishedInterface) {
+      return $workflow->getState($entity->isPublished() ? 'published' : 'draft');
+    }
+    return parent::getInitialState($workflow);
+  }
+
 }
diff --git a/core/modules/content_moderation/src/StateTransitionValidation.php b/core/modules/content_moderation/src/StateTransitionValidation.php
index c4e26c26ff9b..4952f2e7154c 100644
--- a/core/modules/content_moderation/src/StateTransitionValidation.php
+++ b/core/modules/content_moderation/src/StateTransitionValidation.php
@@ -40,7 +40,7 @@ public function __construct(ModerationInformationInterface $moderation_info) {
    */
   public function getValidTransitions(ContentEntityInterface $entity, AccountInterface $user) {
     $workflow = $this->moderationInfo->getWorkflowForEntity($entity);
-    $current_state = $entity->moderation_state->value ? $workflow->getState($entity->moderation_state->value) : $workflow->getInitialState();
+    $current_state = $entity->moderation_state->value ? $workflow->getState($entity->moderation_state->value) : $workflow->getTypePlugin()->getInitialState($workflow, $entity);
 
     return array_filter($current_state->getTransitions(), function(Transition $transition) use ($workflow, $user) {
       return $user->hasPermission('use ' . $workflow->id() . ' transition ' . $transition->id());
diff --git a/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php b/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php
index 70a5df5bcd6b..0f8469921378 100644
--- a/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php
+++ b/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php
@@ -95,6 +95,9 @@ public function testBasicModeration($entity_type_id) {
       'title' => 'Test title',
       $this->entityTypeManager->getDefinition($entity_type_id)->getKey('bundle') => $bundle_id,
     ]);
+    if ($entity instanceof EntityPublishedInterface) {
+      $entity->setUnpublished();
+    }
     $entity->save();
     $entity = $this->reloadEntity($entity);
     $this->assertEquals('draft', $entity->moderation_state->value);
diff --git a/core/modules/content_moderation/tests/src/Kernel/InitialStateTest.php b/core/modules/content_moderation/tests/src/Kernel/InitialStateTest.php
new file mode 100644
index 000000000000..0150d3c6e5f5
--- /dev/null
+++ b/core/modules/content_moderation/tests/src/Kernel/InitialStateTest.php
@@ -0,0 +1,82 @@
+<?php
+
+namespace Drupal\Tests\content_moderation\Kernel;
+
+use Drupal\entity_test\Entity\EntityTestRev;
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\node\Entity\Node;
+use Drupal\node\Entity\NodeType;
+use Drupal\workflows\Entity\Workflow;
+
+/**
+ * Tests the correct initial states are set on install.
+ *
+ * @group content_moderation
+ */
+class InitialStateTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'entity_test',
+    'node',
+    'user',
+    'system',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installSchema('node', 'node_access');
+    $this->installEntitySchema('node');
+    $this->installEntitySchema('user');
+    $this->installEntitySchema('entity_test_rev');
+  }
+
+  /**
+   * Tests the correct initial state.
+   */
+  public function testInitialState() {
+    $node_type = NodeType::create([
+      'type' => 'example',
+    ]);
+    $node_type->save();
+
+    // Test with an entity type that implements EntityPublishedInterface.
+    $unpublished_node = Node::create([
+      'type' => 'example',
+      'title' => 'Unpublished node',
+      'status' => 0,
+    ]);
+    $unpublished_node->save();
+
+    $published_node = Node::create([
+      'type' => 'example',
+      'title' => 'Published node',
+      'status' => 1,
+    ]);
+    $published_node->save();
+
+    // Test with an entity type that doesn't implement EntityPublishedInterface.
+    $entity_test = EntityTestRev::create();
+    $entity_test->save();
+
+    \Drupal::service('module_installer')->install(['content_moderation'], TRUE);
+    $workflow = Workflow::load('editorial');
+    $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
+    $workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
+    $workflow->save();
+
+    $loaded_unpublished_node = Node::load($unpublished_node->id());
+    $loaded_published_node = Node::load($published_node->id());
+    $loaded_entity_test = EntityTestRev::load($entity_test->id());
+    $this->assertEquals('draft', $loaded_unpublished_node->moderation_state->value);
+    $this->assertEquals('published', $loaded_published_node->moderation_state->value);
+    $this->assertEquals('draft', $loaded_entity_test->moderation_state->value);
+  }
+
+}
diff --git a/core/modules/content_moderation/tests/src/Kernel/ModerationStateFieldItemListTest.php b/core/modules/content_moderation/tests/src/Kernel/ModerationStateFieldItemListTest.php
index 3f984da45524..7e9a75c3f412 100644
--- a/core/modules/content_moderation/tests/src/Kernel/ModerationStateFieldItemListTest.php
+++ b/core/modules/content_moderation/tests/src/Kernel/ModerationStateFieldItemListTest.php
@@ -64,7 +64,7 @@ protected function setUp() {
    * Test the field item list when accessing an index.
    */
   public function testArrayIndex() {
-    $this->assertEquals('draft', $this->testNode->moderation_state[0]->value);
+    $this->assertEquals('published', $this->testNode->moderation_state[0]->value);
   }
 
   /**
@@ -75,7 +75,7 @@ public function testArrayIteration() {
     foreach ($this->testNode->moderation_state as $item) {
       $states[] = $item->value;
     }
-    $this->assertEquals(['draft'], $states);
+    $this->assertEquals(['published'], $states);
   }
 
 }
diff --git a/core/modules/workflows/src/Entity/Workflow.php b/core/modules/workflows/src/Entity/Workflow.php
index c6b1ce6a4358..51b8d174f7ea 100644
--- a/core/modules/workflows/src/Entity/Workflow.php
+++ b/core/modules/workflows/src/Entity/Workflow.php
@@ -243,14 +243,6 @@ public function deleteState($state_id) {
     return $this;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getInitialState() {
-    $ordered_states = $this->getStates();
-    return reset($ordered_states);
-  }
-
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/workflows/src/Plugin/WorkflowTypeBase.php b/core/modules/workflows/src/Plugin/WorkflowTypeBase.php
index 59c6b961371b..e87e4d79452a 100644
--- a/core/modules/workflows/src/Plugin/WorkflowTypeBase.php
+++ b/core/modules/workflows/src/Plugin/WorkflowTypeBase.php
@@ -145,4 +145,12 @@ public function onDependencyRemoval(array $dependencies) {
     return FALSE;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getInitialState(WorkflowInterface $workflow) {
+    $ordered_states = $workflow->getStates();
+    return reset($ordered_states);
+  }
+
 }
diff --git a/core/modules/workflows/src/WorkflowInterface.php b/core/modules/workflows/src/WorkflowInterface.php
index d014ddb781de..d156918a6f18 100644
--- a/core/modules/workflows/src/WorkflowInterface.php
+++ b/core/modules/workflows/src/WorkflowInterface.php
@@ -105,14 +105,6 @@ public function setStateWeight($state_id, $weight);
    */
   public function deleteState($state_id);
 
-  /**
-   * Gets the initial state for the workflow.
-   *
-   * @return \Drupal\workflows\StateInterface
-   *   The initial state.
-   */
-  public function getInitialState();
-
   /**
    * Adds a transition to the workflow.
    *
diff --git a/core/modules/workflows/src/WorkflowTypeInterface.php b/core/modules/workflows/src/WorkflowTypeInterface.php
index 0fe668547ce8..2412bf99f438 100644
--- a/core/modules/workflows/src/WorkflowTypeInterface.php
+++ b/core/modules/workflows/src/WorkflowTypeInterface.php
@@ -93,6 +93,17 @@ public function decorateTransition(TransitionInterface $transition);
    */
   public function deleteTransition($transition_id);
 
+  /**
+   * Gets the initial state for the workflow.
+   *
+   * @param \Drupal\workflows\WorkflowInterface $workflow
+   *   The workflow entity.
+   *
+   * @return \Drupal\workflows\StateInterface
+   *   The initial state.
+   */
+  public function getInitialState(WorkflowInterface $workflow);
+
   /**
    * Builds a form to be added to the Workflow state edit form.
    *
diff --git a/core/modules/workflows/tests/src/Functional/WorkflowUiTest.php b/core/modules/workflows/tests/src/Functional/WorkflowUiTest.php
index 3014dd739750..209e9865b5f5 100644
--- a/core/modules/workflows/tests/src/Functional/WorkflowUiTest.php
+++ b/core/modules/workflows/tests/src/Functional/WorkflowUiTest.php
@@ -170,11 +170,11 @@ public function testWorkflowCreation() {
 
     // Ensure that weight changes the state ordering.
     $workflow = $workflow_storage->loadUnchanged('test');
-    $this->assertEquals('published', $workflow->getInitialState()->id());
+    $this->assertEquals('published', $workflow->getTypePlugin()->getInitialState($workflow)->id());
     $this->drupalGet('admin/config/workflow/workflows/manage/test');
     $this->submitForm(['states[draft][weight]' => '-1'], 'Save');
     $workflow = $workflow_storage->loadUnchanged('test');
-    $this->assertEquals('draft', $workflow->getInitialState()->id());
+    $this->assertEquals('draft', $workflow->getTypePlugin()->getInitialState($workflow)->id());
 
     // Verify that we are still on the workflow edit page.
     $this->assertSession()->addressEquals('admin/config/workflow/workflows/manage/test');
diff --git a/core/modules/workflows/tests/src/Unit/WorkflowTest.php b/core/modules/workflows/tests/src/Unit/WorkflowTest.php
index e2a7401cec11..51cb91207007 100644
--- a/core/modules/workflows/tests/src/Unit/WorkflowTest.php
+++ b/core/modules/workflows/tests/src/Unit/WorkflowTest.php
@@ -263,25 +263,6 @@ public function testDeleteOnlyStateException() {
     $workflow->deleteState('draft');
   }
 
-  /**
-   * @covers ::getInitialState
-   */
-  public function testGetInitialState() {
-    $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
-
-    // By default states are ordered in the order added.
-    $workflow
-      ->addState('draft', 'Draft')
-      ->addState('published', 'Published')
-      ->addState('archived', 'Archived');
-
-    $this->assertEquals('draft', $workflow->getInitialState()->id());
-
-    // Make published the first state.
-    $workflow->setStateWeight('published', -1);
-    $this->assertEquals('published', $workflow->getInitialState()->id());
-  }
-
   /**
    * @covers ::addTransition
    * @covers ::hasTransition
-- 
GitLab