Skip to content
Snippets Groups Projects
Commit 7f9dbfe8 authored by Andrei Mateescu's avatar Andrei Mateescu
Browse files

Issue #3224495 by Tim Bozeman, s_leu, amateescu: Prompt users to activate a...

Issue #3224495 by Tim Bozeman, s_leu, amateescu: Prompt users to activate a workspace in the content workflow instead of just denying access to some page
parent 6c0ba219
No related branches found
No related tags found
No related merge requests found
......@@ -9,8 +9,6 @@ use Drupal\Core\Render\Element;
use Drupal\Core\Url;
use Drupal\entity_workflow\Event\EntityWorkflowEvents;
use Drupal\entity_workflow\Event\InitiateTransitionEvent;
use Drupal\views\Form\ViewsForm;
use Drupal\views\Plugin\views\field\BulkForm;
use Drupal\workflows\WorkflowInterface;
/**
......@@ -388,35 +386,6 @@ function entity_workflow_workspace_view_alter(array &$build, EntityInterface $wo
}
}
/**
* Implements hook_form_alter().
*/
function entity_workflow_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
if (\Drupal::service('workspaces.manager')->hasActiveWorkspace()) {
return;
}
$form_object = $form_state->getFormObject();
if ($form_object instanceof ViewsForm) {
$view = $form_state->getBuildInfo()['args'][0];
$bulk_form_field_name = NULL;
foreach ($view->field as $field_name => $field) {
if ($field instanceof BulkForm) {
$bulk_form_field_name = $field_name;
break;
}
}
// Hide Views bulk operations form if we are in Live.
if ($bulk_form_field_name) {
$form[$bulk_form_field_name]['#access'] = FALSE;
$form['header'][$bulk_form_field_name]['#access'] = FALSE;
$form['actions']['#access'] = FALSE;
}
}
}
/**
* Implements hook_theme().
*/
......
......
......@@ -2,7 +2,10 @@
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\views\Form\ViewsForm;
use Drupal\views\Plugin\views\field\BulkForm;
use Drupal\workflows\WorkflowInterface;
use Drupal\workspaces\WorkspaceInterface;
......@@ -111,3 +114,32 @@ function _entity_workflow_content_process_access_hook_results(array $access) {
}
return $result;
}
/**
* Implements hook_form_alter().
*/
function entity_workflow_content_form_alter(&$form, FormStateInterface $form_state, $form_id) {
if (\Drupal::service('workspaces.manager')->hasActiveWorkspace()) {
return;
}
$form_object = $form_state->getFormObject();
if ($form_object instanceof ViewsForm) {
$view = $form_state->getBuildInfo()['args'][0];
$bulk_form_field_name = NULL;
foreach ($view->field as $field_name => $field) {
if ($field instanceof BulkForm) {
$bulk_form_field_name = $field_name;
break;
}
}
// Hide Views bulk operations form if we are in Live.
if ($bulk_form_field_name) {
$form[$bulk_form_field_name]['#access'] = FALSE;
$form['header'][$bulk_form_field_name]['#access'] = FALSE;
$form['actions']['#access'] = FALSE;
}
}
}
services:
entity_workflow_content.route_subscriber:
class: Drupal\entity_workflow_content\Routing\RouteSubscriber
arguments: ['@entity_type.manager', '@entity_workflow.info']
tags:
- { name: event_subscriber }
entity_workflow_content.route_enhancer:
class: Drupal\entity_workflow_content\Routing\RouteEnhancer
arguments: ['@entity_type.manager']
tags:
- { name: route_enhancer }
<?php
namespace Drupal\entity_workflow_content\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\workspaces\Form\WorkspaceSwitcherForm;
use Drupal\wse\Form\WseWorkspaceSwitcherForm;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Allows users to choose a workspace on pages that require one.
*/
class WorkspaceSwitcherController extends ControllerBase implements ContainerInjectionInterface {
/**
* The form builder.
*
* @var \Drupal\Core\Form\FormBuilderInterface
*/
protected $formBuilder;
/**
* Constructs a WorkspaceSwitcherController object.
*
* @param \Drupal\Core\Form\FormBuilderInterface $form_builder
* The form builder.
*/
public function __construct(FormBuilderInterface $form_builder) {
$this->formBuilder = $form_builder;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('form_builder')
);
}
/**
* Provides the workspace switcher form.
*/
public function switcher(Request $request) {
if ($this->moduleHandler()->moduleExists('wse')
&& $this->config('wse.settings')->get('simplified_toolbar_switcher')) {
$switcher_form = WseWorkspaceSwitcherForm::class;
}
else {
$switcher_form = WorkspaceSwitcherForm::class;
}
$form = $this->formBuilder->getForm($switcher_form);
// Hide form elements that are irrelevant for this switcher.
if ($switcher_form === WseWorkspaceSwitcherForm::class) {
$form['workspace_status']['#access'] = FALSE;
}
else {
$form['current']['#access'] = FALSE;
}
return [
'#markup' => $this->t('This action can only be done inside a workspace. Choose one below.'),
'form' => $form,
];
}
}
<?php
namespace Drupal\entity_workflow_content\Routing;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Routing\EnhancerInterface;
use Drupal\Core\Routing\RouteObjectInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Swaps the controller for routes that need to check for an active workspace.
*/
class RouteEnhancer implements EnhancerInterface {
/**
* The entity type manager service.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Constructs a RouteEnhancer object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager service.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
// This service is injected because it's also used by other route enhancers.
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public function enhance(array $defaults, Request $request) {
/** @var \Symfony\Component\Routing\Route $route */
$route = $defaults[RouteObjectInterface::ROUTE_OBJECT];
// Return early if we don't need to require an active workspace.
if (!$route->hasOption('_entity_workflow_content.require_workspace')) {
return $defaults;
}
if (!$this->getWorkspaceManager()->hasActiveWorkspace()) {
$entity_type_id = $route->getOption('_entity_workflow_content.entity_type_id');
// Try to get the bundle name on entity add routes.
if (($bundle_entity_type = $this->entityTypeManager->getDefinition($entity_type_id)->getBundleEntityType()) && isset($defaults[$bundle_entity_type])) {
$bundle = $defaults['_raw_variables']->get($bundle_entity_type);
}
// Try to get the bundle name on entity edit, Layout Builder and
// Entityqueue routes.
if (isset($defaults[$entity_type_id]) && $defaults[$entity_type_id] instanceof EntityInterface) {
$bundle = $defaults[$entity_type_id]->bundle();
}
if (!isset($bundle)) {
$workflow_info = $this->getWorkflowInfo()->getWorkflowsInfoForEntityType($entity_type_id);
}
else {
$workflow_info = $this->getWorkflowInfo()->getWorkflowsInfoForEntityTypeAndBundle($entity_type_id, $bundle);
}
// If the 'content' workflow is enabled for this entity type and bundle,
// swap the controller of the route to our workspace switcher controller.
// When the workspace switcher form is submitted, either by selecting an
// existing workspace or adding a new one, Drupal will redirect to the
// same page, but at that point there will be an active workspace so the
// controller won't be swapped anymore.
if (isset($workflow_info['content'])) {
$defaults['_controller'] = '\Drupal\entity_workflow_content\Controller\WorkspaceSwitcherController::switcher';
}
}
return $defaults;
}
/**
* @return \Drupal\workspaces\WorkspaceManagerInterface
* The workspace manager.
*/
protected function getWorkspaceManager() {
// We're not injecting this service so we don't initialize it unless it's
// actually needed.
return \Drupal::service('workspaces.manager');
}
/**
* @return \Drupal\entity_workflow\EntityWorkflowInfo
* The workflow information service.
*/
protected function getWorkflowInfo() {
// We're not injecting this service so we don't initialize it unless it's
// actually needed.
return \Drupal::service('entity_workflow.info');
}
}
<?php
namespace Drupal\entity_workflow_content\Routing;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Routing\RouteSubscriberBase;
use Drupal\Core\Routing\RoutingEvents;
use Drupal\entity_workflow\EntityWorkflowInfo;
use Symfony\Component\Routing\RouteCollection;
/**
* Subscriber for Entity Workflow Content routes.
*/
class RouteSubscriber extends RouteSubscriberBase {
/**
* The entity type manager service.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The entity workflow information service.
*
* @var \Drupal\entity_workflow\EntityWorkflowInfo
*/
protected $entityWorkflowInfo;
/**
* Constructs a RouteSubscriber object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager service.
* @param \Drupal\entity_workflow\EntityWorkflowInfo $entity_workflow_info
* The entity workflow info service.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityWorkflowInfo $entity_workflow_info) {
$this->entityTypeManager = $entity_type_manager;
$this->entityWorkflowInfo = $entity_workflow_info;
}
/**
* {@inheritdoc}
*/
protected function alterRoutes(RouteCollection $collection) {
foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) {
$workflows_info = $this->entityWorkflowInfo->getWorkflowsInfoForEntityType($entity_type_id);
if (isset($workflows_info['content'])) {
// Ensure that all form operations (e.g. Add/Edit, Layout Builder,
// Entityqueue, etc.) require an active workspace for supported entity
// types.
$this->handleEntityForms($collection, $entity_type);
}
}
}
/**
* Enhances various entity forms in the Live workspace.
*
* @param \Symfony\Component\Routing\RouteCollection $collection
* The route collection.
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type.
*/
protected function handleEntityForms(RouteCollection $collection, EntityTypeInterface $entity_type) {
// Handle entity forms.
foreach ($collection as $route) {
$has_content_workflow = FALSE;
// Handle 'add' forms.
if ($entity_create_requirement = $route->getRequirement('_entity_create_access')) {
[$entity_type_id] = explode(':', $entity_create_requirement);
if ($entity_type_id === $entity_type->id()) {
$has_content_workflow = TRUE;
}
}
// Handle 'edit/delete' forms.
if ($entity_form = $route->getDefault('_entity_form')) {
[$entity_type_id] = explode('.', $entity_form, 2);
if ($entity_type_id === $entity_type->id()) {
$has_content_workflow = TRUE;
}
}
if ($has_content_workflow) {
$route->setOption('_entity_workflow_content.require_workspace', TRUE);
$route->setOption('_entity_workflow_content.entity_type_id', $entity_type->id());
}
}
// Handle Layout Builder forms.
$suffixes = ['view', 'discard_changes', 'revert'];
foreach ($suffixes as $suffix) {
if ($route = $collection->get("layout_builder.overrides.{$entity_type->id()}.$suffix")) {
$route->setOption('_entity_workflow_content.require_workspace', TRUE);
$route->setOption('_entity_workflow_content.entity_type_id', $entity_type->id());
}
}
// Handle Entityqueue forms.
if ($route = $collection->get("entity.{$entity_type->id()}.entityqueue")) {
$route->setOption('_entity_workflow_content.require_workspace', TRUE);
$route->setOption('_entity_workflow_content.entity_type_id', $entity_type->id());
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array {
$events = parent::getSubscribedEvents();
// Ensure that we run after Entityqueue's route subscriber so that we can
// handle those routes as well.
$events[RoutingEvents::ALTER] = ['onAlterRoutes', -215];
return $events;
}
}
......@@ -2,7 +2,6 @@
namespace Drupal\entity_workflow\Routing;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Routing\RouteSubscriberBase;
use Drupal\Core\Routing\RoutingEvents;
......@@ -34,6 +33,8 @@ class RouteSubscriber extends RouteSubscriberBase {
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager service.
* @param \Drupal\entity_workflow\EntityWorkflowInfo $entity_workflow_info
* The entity workflow info service.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityWorkflowInfo $entity_workflow_info) {
$this->entityTypeManager = $entity_type_manager;
......@@ -112,10 +113,6 @@ class RouteSubscriber extends RouteSubscriberBase {
->setOption('parameters', $parameters)
->setOption('_admin_route', TRUE);
$collection->add("entity.$entity_type_id.workflow_transition", $route);
// Disable all form operations (e.g. Edit, Layout Builder, Entityqueue)
// in the Live workspace for supported entity types.
$this->disableEntityForms($collection, $entity_type);
}
}
......@@ -142,66 +139,12 @@ class RouteSubscriber extends RouteSubscriberBase {
}
}
/**
* Disables various entity forms in the Live workspace.
*
* @param \Symfony\Component\Routing\RouteCollection $collection
* The route collection.
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type.
*/
protected function disableEntityForms(RouteCollection $collection, EntityTypeInterface $entity_type) {
if ($entity_type->id() === 'workspace') {
return;
}
// Disable entity forms.
foreach ($collection as $route) {
$needs_active_workspace = FALSE;
// Disable 'add' forms.
if ($entity_create_requirement = $route->getRequirement('_entity_create_access')) {
[$entity_type_id] = explode(':', $entity_create_requirement);
if ($entity_type_id === $entity_type->id()) {
$needs_active_workspace = TRUE;
}
}
// Disable 'edit/delete' forms.
if ($entity_form = $route->getDefault('_entity_form')) {
[$entity_type_id] = explode('.', $entity_form, 2);
if ($entity_type_id === $entity_type->id()) {
$needs_active_workspace = TRUE;
}
}
if ($needs_active_workspace) {
$route->addRequirements(['_has_active_workspace' => 'true']);
}
}
// Disable Layout Builder forms.
$suffixes = ['view', 'discard_changes', 'revert'];
foreach ($suffixes as $suffix) {
if ($route = $collection->get("layout_builder.overrides.{$entity_type->id()}.$suffix")) {
$route->addRequirements(['_has_active_workspace' => 'true']);
}
}
// Disable Entityqueue forms.
if ($route = $collection->get("entity.{$entity_type->id()}.entityqueue")) {
$route->addRequirements(['_has_active_workspace' => 'true']);
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array {
$events = parent::getSubscribedEvents();
// Ensure that we run after Entityqueue's route subscriber so that we can
// disable those routes as well.
$events[RoutingEvents::ALTER] = ['onAlterRoutes', -215];
$events[RoutingEvents::ALTER] = ['onAlterRoutes', -160];
return $events;
}
......
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment