diff --git a/core/modules/workspace/src/Entity/Workspace.php b/core/modules/workspace/src/Entity/Workspace.php index 9c57347..de1b4ec 100644 --- a/core/modules/workspace/src/Entity/Workspace.php +++ b/core/modules/workspace/src/Entity/Workspace.php @@ -9,7 +9,6 @@ use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\user\UserInterface; -use Drupal\workspace\RepositoryHandlerInterface; use Drupal\workspace\WorkspaceInterface; use Drupal\workspace\WorkspaceManager; @@ -27,7 +26,6 @@ * plural = "@count workspaces" * ), * handlers = { - * "storage" = "Drupal\Core\Entity\Sql\SqlContentEntityStorage", * "list_builder" = "\Drupal\workspace\WorkspaceListBuilder", * "access" = "Drupal\workspace\WorkspaceAccessControlHandler", * "route_provider" = { @@ -124,14 +122,22 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { /** * {@inheritdoc} */ - public function getRepositoryHandlerPlugin() { - if (($target = $this->target->value) && $target !== RepositoryHandlerInterface::EMPTY_VALUE) { - $configuration = [ - 'source' => $this->id(), - 'target' => $target, - ]; - return \Drupal::service('plugin.manager.workspace.repository_handler')->createInstance($target, $configuration); - } + public function push() { + return $this->getRepositoryHandler()->push(); + } + + /** + * {@inheritdoc} + */ + public function pull() { + return $this->getRepositoryHandler()->pull(); + } + + /** + * {@inheritdoc} + */ + public function getRepositoryHandler() { + return \Drupal::service('plugin.manager.workspace.repository_handler')->createFromWorkspace($this); } /** diff --git a/core/modules/workspace/src/EntityOperations.php b/core/modules/workspace/src/EntityOperations.php index 57fefe4..601bf20 100644 --- a/core/modules/workspace/src/EntityOperations.php +++ b/core/modules/workspace/src/EntityOperations.php @@ -78,7 +78,7 @@ public function entityLoad(array &$entities, $entity_type_id) { ->groupBy('content_entity_id') ->condition('content_entity_type_id', $entity_type_id) ->condition('content_entity_id', $entity_ids, 'IN') - ->condition('workspace', $active_workspace->id(), '=') + ->condition('workspace', $active_workspace->id()) ->execute(); // Since hook_entity_load() is called on both regular entity load as well as diff --git a/core/modules/workspace/src/EntityTypeInfo.php b/core/modules/workspace/src/EntityTypeInfo.php index 8cea472..ecfcded 100644 --- a/core/modules/workspace/src/EntityTypeInfo.php +++ b/core/modules/workspace/src/EntityTypeInfo.php @@ -99,7 +99,7 @@ public function formAlter(array &$form, FormStateInterface $form_state, $form_id // An entity can only be edited in one workspace. $workspace_id = reset($workspace_ids); - if ($workspace_id != $this->workspaceManager->getActiveWorkspace()->id()) { + if ($workspace_id !== $this->workspaceManager->getActiveWorkspace()->id()) { $workspace = $this->entityTypeManager->getStorage('workspace')->load($workspace_id); $form['#markup'] = $this->t('The content is being edited in the %label workspace.', ['%label' => $workspace->label()]); diff --git a/core/modules/workspace/src/Form/WorkspaceActivateForm.php b/core/modules/workspace/src/Form/WorkspaceActivateForm.php index 4da5cad..ea029c4 100644 --- a/core/modules/workspace/src/Form/WorkspaceActivateForm.php +++ b/core/modules/workspace/src/Form/WorkspaceActivateForm.php @@ -5,6 +5,7 @@ use Drupal\Core\Entity\EntityConfirmFormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Messenger\MessengerInterface; +use Drupal\workspace\WorkspaceAccessException; use Drupal\workspace\WorkspaceManagerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -105,12 +106,11 @@ public function actions(array $form, FormStateInterface $form_state) { public function submitForm(array &$form, FormStateInterface $form_state) { try { $this->workspaceManager->setActiveWorkspace($this->entity); - $this->messenger->addMessage($this->t("@workspace is now the active workspace.", ['@workspace' => $this->entity->label()])); + $this->messenger->addMessage($this->t('%workspace_label is now the active workspace.', ['%workspace_label' => $this->entity->label()])); $form_state->setRedirectUrl($this->entity->toUrl('collection')); } - catch (\Exception $e) { - watchdog_exception('workspace', $e); - $this->messenger->addError($e->getMessage()); + catch (WorkspaceAccessException $e) { + $this->messenger->addError($this->t('You do not have access to activate the %workspace_label workspace.', ['%workspace_label' => $this->entity->label()])); } } diff --git a/core/modules/workspace/src/Form/WorkspaceDeleteForm.php b/core/modules/workspace/src/Form/WorkspaceDeleteForm.php index 43311b2..2d8cbef 100644 --- a/core/modules/workspace/src/Form/WorkspaceDeleteForm.php +++ b/core/modules/workspace/src/Form/WorkspaceDeleteForm.php @@ -13,11 +13,18 @@ class WorkspaceDeleteForm extends ContentEntityDeleteForm { /** + * The workspace entity. + * + * @var \Drupal\workspace\WorkspaceInterface + */ + protected $entity; + + /** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { $form = parent::buildForm($form, $form_state); - $source_rev_diff = $this->entity->getRepositoryHandlerPlugin()->getSourceRevisionDifference(); + $source_rev_diff = $this->entity->getRepositoryHandler()->getSourceRevisionDifference(); $items = []; foreach ($source_rev_diff as $entity_type_id => $revision_ids) { $label = $this->entityTypeManager->getDefinition($entity_type_id)->getLabel(); diff --git a/core/modules/workspace/src/Form/WorkspaceDeployForm.php b/core/modules/workspace/src/Form/WorkspaceDeployForm.php index 7bbf345..742042b 100644 --- a/core/modules/workspace/src/Form/WorkspaceDeployForm.php +++ b/core/modules/workspace/src/Form/WorkspaceDeployForm.php @@ -9,7 +9,6 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Messenger\MessengerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\HttpKernel\Exception\HttpException; /** * Provides the workspace deploy form. @@ -65,12 +64,7 @@ public static function create(ContainerInterface $container) { public function form(array $form, FormStateInterface $form_state) { $form = parent::form($form, $form_state); - $repository_handler = $this->entity->getRepositoryHandlerPlugin(); - - // We can not push or pull if we do not have a valid target. - if (!$repository_handler) { - throw new HttpException(500, 'The specified repository handler plugin does not exist.'); - } + $repository_handler = $this->entity->getRepositoryHandler(); $args = [ '%source_label' => $this->entity->label(), @@ -121,8 +115,9 @@ public function form(array $form, FormStateInterface $form_state) { */ public function actions(array $form, FormStateInterface $form_state) { $elements = parent::actions($form, $form_state); + unset($elements['delete']); - $repositoy_handler = $this->entity->getRepositoryHandlerPlugin(); + $repositoy_handler = $this->entity->getRepositoryHandler(); if (isset($form['deploy'])) { $total_count = $form['deploy']['#total_count']; @@ -167,12 +162,11 @@ public function deploy(array &$form, FormStateInterface $form_state) { $workspace = $this->entity; try { - $workspace->getRepositoryHandlerPlugin()->push(); + $workspace->push(); $this->messenger->addMessage($this->t('Successful deployment.')); } catch (\Exception $e) { - watchdog_exception('workspace', $e); - $this->messenger->addMessage($this->t('Deployment error'), 'error'); + $this->messenger->addMessage($this->t('Deployment failed. All errors have been logged.'), 'error'); } } @@ -188,12 +182,11 @@ public function refresh(array &$form, FormStateInterface $form_state) { $workspace = $this->entity; try { - $workspace->getRepositoryHandlerPlugin()->pull(); + $workspace->pull(); $this->messenger->addMessage($this->t('Refresh successful.')); } catch (\Exception $e) { - watchdog_exception('workspace', $e); - $this->messenger->addMessage($this->t('refresh error'), 'error'); + $this->messenger->addMessage($this->t('Refresh failed. All errors have been logged.'), 'error'); } } diff --git a/core/modules/workspace/src/Form/WorkspaceSwitcherForm.php b/core/modules/workspace/src/Form/WorkspaceSwitcherForm.php index 4e21390..6ac54a2 100644 --- a/core/modules/workspace/src/Form/WorkspaceSwitcherForm.php +++ b/core/modules/workspace/src/Form/WorkspaceSwitcherForm.php @@ -6,6 +6,7 @@ use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Messenger\MessengerInterface; +use Drupal\workspace\WorkspaceAccessException; use Drupal\workspace\WorkspaceManagerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -112,18 +113,6 @@ public function buildForm(array $form, FormStateInterface $form_state) { /** * {@inheritdoc} */ - public function validateForm(array &$form, FormStateInterface $form_state) { - $id = $form_state->getValue('workspace_id'); - - // Ensure the workspace by that ID exists. - if (!$this->workspaceStorage->load($id)) { - $form_state->setErrorByName('workspace_id', $this->t('This workspace does not exist.')); - } - } - - /** - * {@inheritdoc} - */ public function submitForm(array &$form, FormStateInterface $form_state) { $id = $form_state->getValue('workspace_id'); @@ -132,12 +121,11 @@ public function submitForm(array &$form, FormStateInterface $form_state) { try { $this->workspaceManager->setActiveWorkspace($workspace); - $this->messenger->addMessage($this->t("@workspace is now the active workspace.", ['@workspace' => $workspace->label()])); + $this->messenger->addMessage($this->t('%workspace_label is now the active workspace.', ['%workspace_label' => $workspace->label()])); $form_state->setRedirect(''); } - catch (\Exception $e) { - watchdog_exception('workspace', $e); - $this->messenger->addError($e->getMessage()); + catch (WorkspaceAccessException $e) { + $this->messenger->addError($this->t('You do not have access to activate the %workspace_label workspace.', ['%workspace_label' => $workspace->label()])); } } diff --git a/core/modules/workspace/src/Negotiator/DefaultWorkspaceNegotiator.php b/core/modules/workspace/src/Negotiator/DefaultWorkspaceNegotiator.php index e93d0c6..a37a108 100644 --- a/core/modules/workspace/src/Negotiator/DefaultWorkspaceNegotiator.php +++ b/core/modules/workspace/src/Negotiator/DefaultWorkspaceNegotiator.php @@ -52,6 +52,7 @@ public function getActiveWorkspace(Request $request) { $default_workspace = $this->workspaceStorage->create([ 'id' => WorkspaceManager::DEFAULT_WORKSPACE, 'label' => Unicode::ucwords(WorkspaceManager::DEFAULT_WORKSPACE), + 'target' => '', ]); $default_workspace->enforceIsNew(FALSE); diff --git a/core/modules/workspace/src/Plugin/RepositoryHandler/NullRepositoryHandler.php b/core/modules/workspace/src/Plugin/RepositoryHandler/NullRepositoryHandler.php new file mode 100644 index 0000000..33b720d --- /dev/null +++ b/core/modules/workspace/src/Plugin/RepositoryHandler/NullRepositoryHandler.php @@ -0,0 +1,68 @@ +getPluginDefinition()['label']; + } + + /** + * {@inheritdoc} + */ + public function getDescription() { + return $this->getPluginDefinition()['description']; + } + +} diff --git a/core/modules/workspace/src/RepositoryHandlerInterface.php b/core/modules/workspace/src/RepositoryHandlerInterface.php index 6e49fd8..21ab5b4 100644 --- a/core/modules/workspace/src/RepositoryHandlerInterface.php +++ b/core/modules/workspace/src/RepositoryHandlerInterface.php @@ -17,11 +17,6 @@ interface RepositoryHandlerInterface extends PluginInspectionInterface, DerivativeInspectionInterface { /** - * Default empty value for repository handler fields. - */ - const EMPTY_VALUE = '_none'; - - /** * Indicate that an item has been updated both on the source and the target. * * @var int diff --git a/core/modules/workspace/src/RepositoryHandlerManager.php b/core/modules/workspace/src/RepositoryHandlerManager.php index 92777b1..9d92772 100644 --- a/core/modules/workspace/src/RepositoryHandlerManager.php +++ b/core/modules/workspace/src/RepositoryHandlerManager.php @@ -2,20 +2,20 @@ namespace Drupal\workspace; -use Drupal\Component\Plugin\CategorizingPluginManagerInterface; +use Drupal\Component\Plugin\FallbackPluginManagerInterface; use Drupal\Core\Plugin\CategorizingPluginManagerTrait; use Drupal\Core\Plugin\DefaultPluginManager; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Extension\ModuleHandlerInterface; /** - * Provides a Repository Handler Manager for Repository Handlers. + * Provides a plugin manager for Repository Handlers. * * @see \Drupal\workspace\Annotation\RepositoryHandler * @see \Drupal\workspace\RepositoryHandlerInterface * @see plugin_api */ -class RepositoryHandlerManager extends DefaultPluginManager implements CategorizingPluginManagerInterface { +class RepositoryHandlerManager extends DefaultPluginManager implements RepositoryHandlerManagerInterface, FallbackPluginManagerInterface { use CategorizingPluginManagerTrait; @@ -44,4 +44,23 @@ public function processDefinition(&$definition, $plugin_id) { $this->processDefinitionCategory($definition); } + /** + * {@inheritdoc} + */ + public function createFromWorkspace(WorkspaceInterface $workspace) { + $target = $workspace->target->value; + $configuration = [ + 'source' => $workspace->id(), + 'target' => $target, + ]; + return $this->createInstance($target, $configuration); + } + + /** + * {@inheritdoc} + */ + public function getFallbackPluginId($plugin_id, array $configuration = []) { + return 'null'; + } + } diff --git a/core/modules/workspace/src/RepositoryHandlerManagerInterface.php b/core/modules/workspace/src/RepositoryHandlerManagerInterface.php new file mode 100644 index 0000000..ae04e90 --- /dev/null +++ b/core/modules/workspace/src/RepositoryHandlerManagerInterface.php @@ -0,0 +1,23 @@ +getRepositoryHandlerPlugin()) { + if (!$entity->getRepositoryHandler() instanceof NullRepositoryHandler) { $operations['deploy'] = [ 'title' => $this->t('Deploy content'), // The 'Deploy' operation should be the default one for the currently diff --git a/core/modules/workspace/src/WorkspaceManager.php b/core/modules/workspace/src/WorkspaceManager.php index bdba834..7a46234 100644 --- a/core/modules/workspace/src/WorkspaceManager.php +++ b/core/modules/workspace/src/WorkspaceManager.php @@ -175,7 +175,10 @@ public function setActiveWorkspace(WorkspaceInterface $workspace) { // If the current user doesn't have access to view the workspace, they // shouldn't be allowed to switch to it. if (!$workspace->access('view') && !$workspace->isDefaultWorkspace()) { - $this->logger->error('Denied access to view workspace %workspace_label', ['%workspace_label' => $workspace->label()]); + $this->logger->error('Denied access to view workspace %workspace_label for user %uid', [ + '%workspace_label' => $workspace->label(), + '%uid' => $this->currentUser->id(), + ]); throw new WorkspaceAccessException('The user does not have permission to view that workspace.'); } diff --git a/core/modules/workspace/tests/src/Functional/WorkspaceConcurrentEditingTest.php b/core/modules/workspace/tests/src/Functional/WorkspaceConcurrentEditingTest.php index 396aa20..1662eb6 100644 --- a/core/modules/workspace/tests/src/Functional/WorkspaceConcurrentEditingTest.php +++ b/core/modules/workspace/tests/src/Functional/WorkspaceConcurrentEditingTest.php @@ -87,7 +87,7 @@ public function testSwitchingWorkspaces() { // Deploy the changes from the 'Vultures' workspace and check that the node // can be edited again in other workspaces. - $vultures->getRepositoryHandlerPlugin()->push(); + $vultures->getRepositoryHandler()->push(); $this->switchToWorkspace($gravity); $this->drupalGet('/node/' . $test_node->id() . '/edit'); $page = $this->getSession()->getPage(); diff --git a/core/modules/workspace/tests/src/Kernel/WorkspaceIntegrationTest.php b/core/modules/workspace/tests/src/Kernel/WorkspaceIntegrationTest.php index f0d9d64..2a269db 100644 --- a/core/modules/workspace/tests/src/Kernel/WorkspaceIntegrationTest.php +++ b/core/modules/workspace/tests/src/Kernel/WorkspaceIntegrationTest.php @@ -345,7 +345,7 @@ public function testWorkspaces() { $this->assertWorkspaceAssociation($expected_workspace_association['add_published_node_in_stage'], 'node'); // Deploy 'stage' to 'live'. - $stage_repository_handler = $this->workspaces['stage']->getRepositoryHandlerPlugin(); + $stage_repository_handler = $this->workspaces['stage']->getRepositoryHandler(); // Check which revisions need to be pushed. $expected = [ diff --git a/core/modules/workspace/workspace.install b/core/modules/workspace/workspace.install index 0be1294..45cd59c 100644 --- a/core/modules/workspace/workspace.install +++ b/core/modules/workspace/workspace.install @@ -6,7 +6,6 @@ */ use Drupal\workspace\Entity\Workspace; -use Drupal\workspace\RepositoryHandlerInterface; /** * Implements hook_install(). @@ -34,7 +33,7 @@ function workspace_install() { Workspace::create([ 'id' => 'live', 'label' => 'Live', - 'target' => RepositoryHandlerInterface::EMPTY_VALUE, + 'target' => '', 'uid' => $owner_id, ])->save();