From 51f471d8fbe5a69ccd87b6657579b0ffd96187d4 Mon Sep 17 00:00:00 2001
From: catch <catch@35733.no-reply.drupal.org>
Date: Sun, 21 Apr 2024 09:19:06 +0100
Subject: [PATCH] Issue #3208390 by amateescu, s_leu, Fabianx, tim.plunkett,
 xjm, smustgrave, alexpott, catch, joachim, EclipseGc: Add an API for allowing
 modules to mark their forms as workspace-safe

---
 .../WorkspaceDynamicSafeFormInterface.php     | 30 +++++++++++++++++++
 .../Core/Form/WorkspaceSafeFormInterface.php  | 15 ++++++++++
 .../src/Form/ConfigureBlockFormBase.php       |  4 +--
 .../src/Form/ConfigureSectionForm.php         |  4 +--
 .../src/Form/DiscardLayoutChangesForm.php     |  4 +--
 .../src/Form/LayoutBuilderDisableForm.php     |  4 +--
 .../src/Form/LayoutRebuildConfirmFormBase.php |  4 +--
 .../layout_builder/src/Form/MoveBlockForm.php |  4 +--
 .../src/Form/OverridesEntityForm.php          |  4 +--
 .../src/Form/RevertOverridesForm.php          |  4 +--
 .../src/Form/WorkspaceSafeFormTrait.php       | 19 +++++++-----
 .../search/src/Form/SearchBlockForm.php       |  3 +-
 .../search/src/Form/SearchPageForm.php        |  3 +-
 .../views/src/Form/ViewsExposedForm.php       |  3 +-
 .../workspaces/src/Form/SwitchToLiveForm.php  |  3 +-
 .../src/Form/WorkspaceActivateForm.php        |  3 +-
 .../src/Form/WorkspaceDeleteForm.php          |  2 +-
 .../workspaces/src/Form/WorkspaceForm.php     |  2 +-
 .../src/Form/WorkspaceFormInterface.php       |  6 ++++
 .../src/Form/WorkspaceMergeForm.php           |  3 +-
 .../src/Form/WorkspacePublishForm.php         |  3 +-
 .../src/Form/WorkspaceSwitcherForm.php        |  3 +-
 .../modules/workspaces/src/FormOperations.php | 22 ++++----------
 23 files changed, 102 insertions(+), 50 deletions(-)
 create mode 100644 core/lib/Drupal/Core/Form/WorkspaceDynamicSafeFormInterface.php
 create mode 100644 core/lib/Drupal/Core/Form/WorkspaceSafeFormInterface.php

diff --git a/core/lib/Drupal/Core/Form/WorkspaceDynamicSafeFormInterface.php b/core/lib/Drupal/Core/Form/WorkspaceDynamicSafeFormInterface.php
new file mode 100644
index 000000000000..1deae10c7ec9
--- /dev/null
+++ b/core/lib/Drupal/Core/Form/WorkspaceDynamicSafeFormInterface.php
@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\Core\Form;
+
+/**
+ * Defines an interface for forms that can be workspace-safe.
+ *
+ * This interface should be used by forms that have to determine whether they're
+ * workspace-safe based on dynamic criteria.
+ *
+ * @see \Drupal\Core\Form\WorkspaceSafeFormInterface
+ */
+interface WorkspaceDynamicSafeFormInterface extends FormInterface {
+
+  /**
+   * Determines whether the form is safe to be submitted in a workspace.
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   *
+   * @return bool
+   *   TRUE if the form is workspace-safe, FALSE otherwise.
+   */
+  public function isWorkspaceSafeForm(array $form, FormStateInterface $form_state): bool;
+
+}
diff --git a/core/lib/Drupal/Core/Form/WorkspaceSafeFormInterface.php b/core/lib/Drupal/Core/Form/WorkspaceSafeFormInterface.php
new file mode 100644
index 000000000000..b7b95b30b083
--- /dev/null
+++ b/core/lib/Drupal/Core/Form/WorkspaceSafeFormInterface.php
@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\Core\Form;
+
+/**
+ * Defines an interface for forms that are safe to be submitted in a workspace.
+ *
+ * A form is considered workspace-safe if its submission has no impact on the
+ * Live site.
+ *
+ * @see \Drupal\Core\Form\WorkspaceDynamicSafeFormInterface
+ */
+interface WorkspaceSafeFormInterface extends FormInterface {}
diff --git a/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php b/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php
index 4be13361aff4..cc5a8f139576 100644
--- a/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php
+++ b/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Form\SubformState;
+use Drupal\Core\Form\WorkspaceDynamicSafeFormInterface;
 use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
 use Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait;
 use Drupal\Core\Plugin\ContextAwarePluginInterface;
@@ -29,7 +30,7 @@
  * @internal
  *   Form classes are internal.
  */
-abstract class ConfigureBlockFormBase extends FormBase implements BaseFormIdInterface {
+abstract class ConfigureBlockFormBase extends FormBase implements BaseFormIdInterface, WorkspaceDynamicSafeFormInterface {
 
   use AjaxFormHelperTrait;
   use ContextAwarePluginAssignmentTrait;
@@ -164,7 +165,6 @@ public function doBuildForm(array $form, FormStateInterface $form_state, Section
     $this->delta = $delta;
     $this->uuid = $component->getUuid();
     $this->block = $component->getPlugin();
-    $this->markWorkspaceSafe($form_state);
 
     $form_state->setTemporaryValue('gathered_contexts', $this->getPopulatedContexts($section_storage));
 
diff --git a/core/modules/layout_builder/src/Form/ConfigureSectionForm.php b/core/modules/layout_builder/src/Form/ConfigureSectionForm.php
index 42166abc1fbf..6a6866885a33 100644
--- a/core/modules/layout_builder/src/Form/ConfigureSectionForm.php
+++ b/core/modules/layout_builder/src/Form/ConfigureSectionForm.php
@@ -7,6 +7,7 @@
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Form\SubformState;
+use Drupal\Core\Form\WorkspaceDynamicSafeFormInterface;
 use Drupal\Core\Layout\LayoutInterface;
 use Drupal\Core\Plugin\ContextAwarePluginInterface;
 use Drupal\Core\Plugin\PluginFormFactoryInterface;
@@ -26,7 +27,7 @@
  * @internal
  *   Form classes are internal.
  */
-class ConfigureSectionForm extends FormBase {
+class ConfigureSectionForm extends FormBase implements WorkspaceDynamicSafeFormInterface {
 
   use AjaxFormHelperTrait;
   use LayoutBuilderContextTrait;
@@ -128,7 +129,6 @@ public function buildForm(array $form, FormStateInterface $form_state, SectionSt
     $this->delta = $delta;
     $this->isUpdate = is_null($plugin_id);
     $this->pluginId = $plugin_id;
-    $this->markWorkspaceSafe($form_state);
 
     $section = $this->getCurrentSection();
 
diff --git a/core/modules/layout_builder/src/Form/DiscardLayoutChangesForm.php b/core/modules/layout_builder/src/Form/DiscardLayoutChangesForm.php
index 2befa97d3b0a..72eb56ed6733 100644
--- a/core/modules/layout_builder/src/Form/DiscardLayoutChangesForm.php
+++ b/core/modules/layout_builder/src/Form/DiscardLayoutChangesForm.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\WorkspaceDynamicSafeFormInterface;
 use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
 use Drupal\layout_builder\SectionStorageInterface;
@@ -15,7 +16,7 @@
  * @internal
  *   Form classes are internal.
  */
-class DiscardLayoutChangesForm extends ConfirmFormBase {
+class DiscardLayoutChangesForm extends ConfirmFormBase implements WorkspaceDynamicSafeFormInterface {
 
   use WorkspaceSafeFormTrait;
 
@@ -89,7 +90,6 @@ public function getCancelUrl() {
    */
   public function buildForm(array $form, FormStateInterface $form_state, SectionStorageInterface $section_storage = NULL) {
     $this->sectionStorage = $section_storage;
-    $this->markWorkspaceSafe($form_state);
     // Mark this as an administrative page for JavaScript ("Back to site" link).
     $form['#attached']['drupalSettings']['path']['currentPathIsAdmin'] = TRUE;
     return parent::buildForm($form, $form_state);
diff --git a/core/modules/layout_builder/src/Form/LayoutBuilderDisableForm.php b/core/modules/layout_builder/src/Form/LayoutBuilderDisableForm.php
index 2f7173fb30a7..117a4663e78f 100644
--- a/core/modules/layout_builder/src/Form/LayoutBuilderDisableForm.php
+++ b/core/modules/layout_builder/src/Form/LayoutBuilderDisableForm.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\WorkspaceDynamicSafeFormInterface;
 use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\layout_builder\DefaultsSectionStorageInterface;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
@@ -16,7 +17,7 @@
  * @internal
  *   Form classes are internal.
  */
-class LayoutBuilderDisableForm extends ConfirmFormBase {
+class LayoutBuilderDisableForm extends ConfirmFormBase implements WorkspaceDynamicSafeFormInterface {
 
   use WorkspaceSafeFormTrait;
 
@@ -94,7 +95,6 @@ public function buildForm(array $form, FormStateInterface $form_state, SectionSt
     }
 
     $this->sectionStorage = $section_storage;
-    $this->markWorkspaceSafe($form_state);
     // Mark this as an administrative page for JavaScript ("Back to site" link).
     $form['#attached']['drupalSettings']['path']['currentPathIsAdmin'] = TRUE;
     return parent::buildForm($form, $form_state);
diff --git a/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php b/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php
index 8e7cbf4b450d..98875bed4088 100644
--- a/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php
+++ b/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Ajax\AjaxFormHelperTrait;
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\WorkspaceDynamicSafeFormInterface;
 use Drupal\layout_builder\Controller\LayoutRebuildTrait;
 use Drupal\layout_builder\LayoutBuilderHighlightTrait;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
@@ -17,7 +18,7 @@
  * @internal
  *   Form classes are internal.
  */
-abstract class LayoutRebuildConfirmFormBase extends ConfirmFormBase {
+abstract class LayoutRebuildConfirmFormBase extends ConfirmFormBase implements WorkspaceDynamicSafeFormInterface {
 
   use AjaxFormHelperTrait;
   use LayoutBuilderHighlightTrait;
@@ -78,7 +79,6 @@ public function buildForm(array $form, FormStateInterface $form_state, SectionSt
     $this->sectionStorage = $section_storage;
     $this->delta = $delta;
 
-    $this->markWorkspaceSafe($form_state);
     $form = parent::buildForm($form, $form_state);
 
     if ($this->isAjax()) {
diff --git a/core/modules/layout_builder/src/Form/MoveBlockForm.php b/core/modules/layout_builder/src/Form/MoveBlockForm.php
index 574f2c5d0d73..3c572509a77d 100644
--- a/core/modules/layout_builder/src/Form/MoveBlockForm.php
+++ b/core/modules/layout_builder/src/Form/MoveBlockForm.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Ajax\AjaxFormHelperTrait;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\WorkspaceDynamicSafeFormInterface;
 use Drupal\layout_builder\Context\LayoutBuilderContextTrait;
 use Drupal\layout_builder\Controller\LayoutRebuildTrait;
 use Drupal\layout_builder\LayoutBuilderHighlightTrait;
@@ -18,7 +19,7 @@
  * @internal
  *   Form classes are internal.
  */
-class MoveBlockForm extends FormBase {
+class MoveBlockForm extends FormBase implements WorkspaceDynamicSafeFormInterface {
 
   use AjaxFormHelperTrait;
   use LayoutBuilderContextTrait;
@@ -118,7 +119,6 @@ public function buildForm(array $form, FormStateInterface $form_state, SectionSt
     $this->delta = $delta;
     $this->uuid = $uuid;
     $this->region = $region;
-    $this->markWorkspaceSafe($form_state);
 
     $form['#attributes']['data-layout-builder-target-highlight-id'] = $this->blockUpdateHighlightId($uuid);
 
diff --git a/core/modules/layout_builder/src/Form/OverridesEntityForm.php b/core/modules/layout_builder/src/Form/OverridesEntityForm.php
index 77743a3c585d..e4e15914446e 100644
--- a/core/modules/layout_builder/src/Form/OverridesEntityForm.php
+++ b/core/modules/layout_builder/src/Form/OverridesEntityForm.php
@@ -9,6 +9,7 @@
 use Drupal\Core\Entity\EntityRepositoryInterface;
 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\WorkspaceDynamicSafeFormInterface;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
 use Drupal\layout_builder\OverridesSectionStorageInterface;
 use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage;
@@ -21,7 +22,7 @@
  * @internal
  *   Form classes are internal.
  */
-class OverridesEntityForm extends ContentEntityForm {
+class OverridesEntityForm extends ContentEntityForm implements WorkspaceDynamicSafeFormInterface {
 
   use PreviewToggleTrait;
   use LayoutBuilderEntityFormTrait;
@@ -91,7 +92,6 @@ protected function init(FormStateInterface $form_state) {
    */
   public function buildForm(array $form, FormStateInterface $form_state, SectionStorageInterface $section_storage = NULL) {
     $this->sectionStorage = $section_storage;
-    $this->markWorkspaceSafe($form_state);
     $form = parent::buildForm($form, $form_state);
     $form['#attributes']['class'][] = 'layout-builder-form';
 
diff --git a/core/modules/layout_builder/src/Form/RevertOverridesForm.php b/core/modules/layout_builder/src/Form/RevertOverridesForm.php
index 9375904e0e62..9c8932d63634 100644
--- a/core/modules/layout_builder/src/Form/RevertOverridesForm.php
+++ b/core/modules/layout_builder/src/Form/RevertOverridesForm.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\WorkspaceDynamicSafeFormInterface;
 use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
 use Drupal\layout_builder\OverridesSectionStorageInterface;
@@ -16,7 +17,7 @@
  * @internal
  *   Form classes are internal.
  */
-class RevertOverridesForm extends ConfirmFormBase {
+class RevertOverridesForm extends ConfirmFormBase implements WorkspaceDynamicSafeFormInterface {
 
   use WorkspaceSafeFormTrait;
 
@@ -101,7 +102,6 @@ public function buildForm(array $form, FormStateInterface $form_state, SectionSt
     }
 
     $this->sectionStorage = $section_storage;
-    $this->markWorkspaceSafe($form_state);
     // Mark this as an administrative page for JavaScript ("Back to site" link).
     $form['#attached']['drupalSettings']['path']['currentPathIsAdmin'] = TRUE;
     return parent::buildForm($form, $form_state);
diff --git a/core/modules/layout_builder/src/Form/WorkspaceSafeFormTrait.php b/core/modules/layout_builder/src/Form/WorkspaceSafeFormTrait.php
index f93986b99c8f..5cffd8bdf10a 100644
--- a/core/modules/layout_builder/src/Form/WorkspaceSafeFormTrait.php
+++ b/core/modules/layout_builder/src/Form/WorkspaceSafeFormTrait.php
@@ -19,16 +19,17 @@ trait WorkspaceSafeFormTrait {
   protected ?WorkspaceInformationInterface $workspaceInfo = NULL;
 
   /**
-   * Marks a form as workspace-safe, if possible.
+   * Determines whether the current form is safe to be submitted in a workspace.
    *
+   * @param array $form
+   *   An associative array containing the structure of the form.
    * @param \Drupal\Core\Form\FormStateInterface $form_state
-   *   The form state object.
+   *   The current state of the form.
+   *
+   * @return bool
+   *   TRUE if the form is workspace-safe, FALSE otherwise.
    */
-  protected function markWorkspaceSafe(FormStateInterface $form_state): void {
-    if (!\Drupal::hasService('workspaces.information')) {
-      return;
-    }
-
+  public function isWorkspaceSafeForm(array $form, FormStateInterface $form_state): bool {
     $section_storage = $this->sectionStorage ?: $this->getSectionStorageFromFormState($form_state);
     if ($section_storage) {
       $context_definitions = $section_storage->getContextDefinitions();
@@ -39,10 +40,12 @@ protected function markWorkspaceSafe(FormStateInterface $form_state): void {
         $ignored = $entity && $this->getWorkspaceInfo()->isEntityIgnored($entity);
 
         if ($supported || $ignored) {
-          $form_state->set('workspace_safe', TRUE);
+          return TRUE;
         }
       }
     }
+
+    return FALSE;
   }
 
   /**
diff --git a/core/modules/search/src/Form/SearchBlockForm.php b/core/modules/search/src/Form/SearchBlockForm.php
index 4edcd73a1049..1ded36fe420b 100644
--- a/core/modules/search/src/Form/SearchBlockForm.php
+++ b/core/modules/search/src/Form/SearchBlockForm.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\WorkspaceSafeFormInterface;
 use Drupal\Core\Render\RendererInterface;
 use Drupal\Core\Url;
 use Drupal\search\SearchPageRepositoryInterface;
@@ -15,7 +16,7 @@
  *
  * @internal
  */
-class SearchBlockForm extends FormBase {
+class SearchBlockForm extends FormBase implements WorkspaceSafeFormInterface {
 
   /**
    * The search page repository.
diff --git a/core/modules/search/src/Form/SearchPageForm.php b/core/modules/search/src/Form/SearchPageForm.php
index 4f627d91e812..06aa988ae2e7 100644
--- a/core/modules/search/src/Form/SearchPageForm.php
+++ b/core/modules/search/src/Form/SearchPageForm.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\WorkspaceSafeFormInterface;
 use Drupal\Core\Url;
 use Drupal\search\SearchPageInterface;
 
@@ -18,7 +19,7 @@
  *
  * @internal
  */
-class SearchPageForm extends FormBase {
+class SearchPageForm extends FormBase implements WorkspaceSafeFormInterface {
 
   /**
    * The search page entity.
diff --git a/core/modules/views/src/Form/ViewsExposedForm.php b/core/modules/views/src/Form/ViewsExposedForm.php
index 417d97971e92..d68b1dd5363c 100644
--- a/core/modules/views/src/Form/ViewsExposedForm.php
+++ b/core/modules/views/src/Form/ViewsExposedForm.php
@@ -5,6 +5,7 @@
 use Drupal\Component\Utility\Html;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\WorkspaceSafeFormInterface;
 use Drupal\Core\Path\CurrentPathStack;
 use Drupal\Core\Render\Element\Checkboxes;
 use Drupal\Core\Url;
@@ -16,7 +17,7 @@
  *
  * @internal
  */
-class ViewsExposedForm extends FormBase {
+class ViewsExposedForm extends FormBase implements WorkspaceSafeFormInterface {
 
   /**
    * The exposed form cache.
diff --git a/core/modules/workspaces/src/Form/SwitchToLiveForm.php b/core/modules/workspaces/src/Form/SwitchToLiveForm.php
index 4cbc5f964cd8..74ab6761043b 100644
--- a/core/modules/workspaces/src/Form/SwitchToLiveForm.php
+++ b/core/modules/workspaces/src/Form/SwitchToLiveForm.php
@@ -5,6 +5,7 @@
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\WorkspaceSafeFormInterface;
 use Drupal\Core\Url;
 use Drupal\workspaces\WorkspaceManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -12,7 +13,7 @@
 /**
  * Provides a form that switches to the live version of the site.
  */
-class SwitchToLiveForm extends ConfirmFormBase implements WorkspaceFormInterface, ContainerInjectionInterface {
+class SwitchToLiveForm extends ConfirmFormBase implements ContainerInjectionInterface, WorkspaceSafeFormInterface {
 
   /**
    * The workspace manager.
diff --git a/core/modules/workspaces/src/Form/WorkspaceActivateForm.php b/core/modules/workspaces/src/Form/WorkspaceActivateForm.php
index 83d48164b776..56fee541ea2e 100644
--- a/core/modules/workspaces/src/Form/WorkspaceActivateForm.php
+++ b/core/modules/workspaces/src/Form/WorkspaceActivateForm.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Entity\EntityConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\WorkspaceSafeFormInterface;
 use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\workspaces\WorkspaceAccessException;
@@ -14,7 +15,7 @@
 /**
  * Handle activation of a workspace on administrative pages.
  */
-class WorkspaceActivateForm extends EntityConfirmFormBase implements WorkspaceFormInterface {
+class WorkspaceActivateForm extends EntityConfirmFormBase implements WorkspaceSafeFormInterface {
 
   /**
    * The workspace entity.
diff --git a/core/modules/workspaces/src/Form/WorkspaceDeleteForm.php b/core/modules/workspaces/src/Form/WorkspaceDeleteForm.php
index c121e3cb1fc3..4fdb1b691258 100644
--- a/core/modules/workspaces/src/Form/WorkspaceDeleteForm.php
+++ b/core/modules/workspaces/src/Form/WorkspaceDeleteForm.php
@@ -16,7 +16,7 @@
  *
  * @internal
  */
-class WorkspaceDeleteForm extends ContentEntityDeleteForm implements WorkspaceFormInterface {
+class WorkspaceDeleteForm extends ContentEntityDeleteForm {
 
   /**
    * The workspace entity.
diff --git a/core/modules/workspaces/src/Form/WorkspaceForm.php b/core/modules/workspaces/src/Form/WorkspaceForm.php
index 8fb6b34ec931..97e3cb0aa1d5 100644
--- a/core/modules/workspaces/src/Form/WorkspaceForm.php
+++ b/core/modules/workspaces/src/Form/WorkspaceForm.php
@@ -12,7 +12,7 @@
 /**
  * Form controller for the workspace edit forms.
  */
-class WorkspaceForm extends ContentEntityForm implements WorkspaceFormInterface {
+class WorkspaceForm extends ContentEntityForm {
 
   /**
    * The workspace entity.
diff --git a/core/modules/workspaces/src/Form/WorkspaceFormInterface.php b/core/modules/workspaces/src/Form/WorkspaceFormInterface.php
index 53f82fa4f27c..8478115a7bdf 100644
--- a/core/modules/workspaces/src/Form/WorkspaceFormInterface.php
+++ b/core/modules/workspaces/src/Form/WorkspaceFormInterface.php
@@ -8,5 +8,11 @@
  * Defines interface for workspace forms so they can be easily distinguished.
  *
  * @internal
+ *
+ * @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Use
+ *   \Drupal\Core\Form\WorkspaceSafeFormInterface or
+ *   \Drupal\Core\Form\WorkspaceDynamicSafeFormInterface instead.
+ *
+ * @see https://www.drupal.org/node/3229111
  */
 interface WorkspaceFormInterface extends FormInterface {}
diff --git a/core/modules/workspaces/src/Form/WorkspaceMergeForm.php b/core/modules/workspaces/src/Form/WorkspaceMergeForm.php
index e447abcaf916..046a1a13d78d 100644
--- a/core/modules/workspaces/src/Form/WorkspaceMergeForm.php
+++ b/core/modules/workspaces/src/Form/WorkspaceMergeForm.php
@@ -6,6 +6,7 @@
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\WorkspaceSafeFormInterface;
 use Drupal\Core\Url;
 use Drupal\workspaces\WorkspaceInterface;
 use Drupal\workspaces\WorkspaceOperationFactory;
@@ -14,7 +15,7 @@
 /**
  * Provides a form that merges the contents for a workspace into another one.
  */
-class WorkspaceMergeForm extends ConfirmFormBase implements WorkspaceFormInterface, ContainerInjectionInterface {
+class WorkspaceMergeForm extends ConfirmFormBase implements ContainerInjectionInterface, WorkspaceSafeFormInterface {
 
   /**
    * The source workspace entity.
diff --git a/core/modules/workspaces/src/Form/WorkspacePublishForm.php b/core/modules/workspaces/src/Form/WorkspacePublishForm.php
index 077e1c857a66..35570089bab8 100644
--- a/core/modules/workspaces/src/Form/WorkspacePublishForm.php
+++ b/core/modules/workspaces/src/Form/WorkspacePublishForm.php
@@ -6,6 +6,7 @@
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\WorkspaceSafeFormInterface;
 use Drupal\Core\Url;
 use Drupal\workspaces\WorkspaceAccessException;
 use Drupal\workspaces\WorkspaceInterface;
@@ -15,7 +16,7 @@
 /**
  * Provides the workspace publishing form.
  */
-class WorkspacePublishForm extends ConfirmFormBase implements WorkspaceFormInterface, ContainerInjectionInterface {
+class WorkspacePublishForm extends ConfirmFormBase implements ContainerInjectionInterface, WorkspaceSafeFormInterface {
 
   /**
    * The workspace that will be published.
diff --git a/core/modules/workspaces/src/Form/WorkspaceSwitcherForm.php b/core/modules/workspaces/src/Form/WorkspaceSwitcherForm.php
index 186aed1b78a7..bfde0f4631c7 100644
--- a/core/modules/workspaces/src/Form/WorkspaceSwitcherForm.php
+++ b/core/modules/workspaces/src/Form/WorkspaceSwitcherForm.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\WorkspaceSafeFormInterface;
 use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\workspaces\WorkspaceAccessException;
 use Drupal\workspaces\WorkspaceManagerInterface;
@@ -13,7 +14,7 @@
 /**
  * Provides a form that activates a different workspace.
  */
-class WorkspaceSwitcherForm extends FormBase implements WorkspaceFormInterface {
+class WorkspaceSwitcherForm extends FormBase implements WorkspaceSafeFormInterface {
 
   /**
    * The workspace manager.
diff --git a/core/modules/workspaces/src/FormOperations.php b/core/modules/workspaces/src/FormOperations.php
index 36493abaa41a..6d06ec6aa058 100644
--- a/core/modules/workspaces/src/FormOperations.php
+++ b/core/modules/workspaces/src/FormOperations.php
@@ -4,10 +4,10 @@
 
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\WorkspaceDynamicSafeFormInterface;
+use Drupal\Core\Form\WorkspaceSafeFormInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
-use Drupal\views\Form\ViewsExposedForm;
-use Drupal\workspaces\Form\WorkspaceFormInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -61,28 +61,18 @@ public function formAlter(array &$form, FormStateInterface $form_state, $form_id
       return;
     }
 
-    // Add an additional validation step for every form if we are in a
-    // non-default workspace.
+    // Add a validation step for every form if we are in a workspace.
     $this->addWorkspaceValidation($form);
 
     // If a form has already been marked as safe or not to submit in a
-    // non-default workspace, we don't have anything else to do.
+    // workspace, we don't have anything else to do.
     if ($form_state->has('workspace_safe')) {
       return;
     }
 
-    // No forms are safe to submit in a non-default workspace by default, except
-    // for the whitelisted ones defined below.
-    $workspace_safe = FALSE;
-
-    // Whitelist a few forms that we know are safe to submit.
     $form_object = $form_state->getFormObject();
-    $is_workspace_form = $form_object instanceof WorkspaceFormInterface;
-    $is_search_form = in_array($form_object->getFormId(), ['search_block_form', 'search_form'], TRUE);
-    $is_views_exposed_form = $form_object instanceof ViewsExposedForm;
-    if ($is_workspace_form || $is_search_form || $is_views_exposed_form) {
-      $workspace_safe = TRUE;
-    }
+    $workspace_safe = $form_object instanceof WorkspaceSafeFormInterface
+      || ($form_object instanceof WorkspaceDynamicSafeFormInterface && $form_object->isWorkspaceSafeForm($form, $form_state));
 
     $form_state->set('workspace_safe', $workspace_safe);
   }
-- 
GitLab