WorkspaceManager.php in Drupal 9
File
core/modules/workspaces/src/WorkspaceManager.php
View source
<?php
namespace Drupal\workspaces;
use Drupal\Core\Cache\MemoryCache\MemoryCacheInterface;
use Drupal\Core\DependencyInjection\ClassResolverInterface;
use Drupal\Core\Entity\EntityPublishedInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\Site\Settings;
use Drupal\Core\State\StateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
class WorkspaceManager implements WorkspaceManagerInterface {
use StringTranslationTrait;
protected $supported = [
'workspace' => FALSE,
];
protected $requestStack;
protected $entityTypeManager;
protected $entityMemoryCache;
protected $currentUser;
protected $state;
protected $logger;
protected $classResolver;
protected $workspaceAssociation;
protected $negotiatorIds;
protected $activeWorkspace;
public function __construct(RequestStack $request_stack, EntityTypeManagerInterface $entity_type_manager, MemoryCacheInterface $entity_memory_cache, AccountProxyInterface $current_user, StateInterface $state, LoggerInterface $logger, ClassResolverInterface $class_resolver, WorkspaceAssociationInterface $workspace_association, array $negotiator_ids) {
$this->requestStack = $request_stack;
$this->entityTypeManager = $entity_type_manager;
$this->entityMemoryCache = $entity_memory_cache;
$this->currentUser = $current_user;
$this->state = $state;
$this->logger = $logger;
$this->classResolver = $class_resolver;
$this->workspaceAssociation = $workspace_association;
$this->negotiatorIds = $negotiator_ids;
}
public function isEntityTypeSupported(EntityTypeInterface $entity_type) {
$entity_type_id = $entity_type
->id();
if (!isset($this->supported[$entity_type_id])) {
$this->supported[$entity_type_id] = $entity_type
->entityClassImplements(EntityPublishedInterface::class) && $entity_type
->isRevisionable();
}
return $this->supported[$entity_type_id];
}
public function getSupportedEntityTypes() {
$entity_types = [];
foreach ($this->entityTypeManager
->getDefinitions() as $entity_type_id => $entity_type) {
if ($this
->isEntityTypeSupported($entity_type)) {
$entity_types[$entity_type_id] = $entity_type;
}
}
return $entity_types;
}
public function hasActiveWorkspace() {
return $this
->getActiveWorkspace() !== FALSE;
}
public function getActiveWorkspace() {
if (!isset($this->activeWorkspace)) {
$request = $this->requestStack
->getCurrentRequest();
foreach ($this->negotiatorIds as $negotiator_id) {
$negotiator = $this->classResolver
->getInstanceFromDefinition($negotiator_id);
if ($negotiator
->applies($request)) {
if (($negotiated_workspace = $negotiator
->getActiveWorkspace($request)) && $negotiated_workspace
->access('view')) {
$active_workspace = $negotiated_workspace;
break;
}
}
}
$this->activeWorkspace = $active_workspace ?? FALSE;
}
return $this->activeWorkspace;
}
public function setActiveWorkspace(WorkspaceInterface $workspace) {
$this
->doSwitchWorkspace($workspace);
$request = $this->requestStack
->getCurrentRequest();
foreach ($this->negotiatorIds as $negotiator_id) {
$negotiator = $this->classResolver
->getInstanceFromDefinition($negotiator_id);
if ($negotiator
->applies($request)) {
$negotiator
->setActiveWorkspace($workspace);
break;
}
}
return $this;
}
public function switchToLive() {
$this
->doSwitchWorkspace(NULL);
foreach ($this->negotiatorIds as $negotiator_id) {
$negotiator = $this->classResolver
->getInstanceFromDefinition($negotiator_id);
$negotiator
->unsetActiveWorkspace();
}
return $this;
}
protected function doSwitchWorkspace($workspace) {
if ($workspace && !$workspace
->access('view')) {
$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.');
}
$this->activeWorkspace = $workspace ?: FALSE;
$cache_tags_to_invalidate = array_map(function ($entity_type_id) {
return 'entity.memory_cache:' . $entity_type_id;
}, array_keys($this
->getSupportedEntityTypes()));
$this->entityMemoryCache
->invalidateTags($cache_tags_to_invalidate);
\Drupal::service('path_alias.manager')
->cacheClear();
}
public function executeInWorkspace($workspace_id, callable $function) {
$workspace = $this->entityTypeManager
->getStorage('workspace')
->load($workspace_id);
if (!$workspace) {
throw new \InvalidArgumentException('The ' . $workspace_id . ' workspace does not exist.');
}
$previous_active_workspace = $this
->getActiveWorkspace();
$this
->doSwitchWorkspace($workspace);
$result = $function();
$this
->doSwitchWorkspace($previous_active_workspace);
return $result;
}
public function executeOutsideWorkspace(callable $function) {
$previous_active_workspace = $this
->getActiveWorkspace();
$this
->doSwitchWorkspace(NULL);
$result = $function();
$this
->doSwitchWorkspace($previous_active_workspace);
return $result;
}
public function shouldAlterOperations(EntityTypeInterface $entity_type) {
return $this
->isEntityTypeSupported($entity_type) && $this
->hasActiveWorkspace();
}
public function purgeDeletedWorkspacesBatch() {
$deleted_workspace_ids = $this->state
->get('workspace.deleted', []);
if (empty($deleted_workspace_ids)) {
return;
}
$batch_size = Settings::get('entity_update_batch_size', 50);
$workspace_id = reset($deleted_workspace_ids);
$tracked_entities = $this->workspaceAssociation
->getTrackedEntities($workspace_id);
$count = 1;
foreach ($tracked_entities as $entity_type_id => $entities) {
$associated_entity_storage = $this->entityTypeManager
->getStorage($entity_type_id);
$associated_revisions = $this->workspaceAssociation
->getAssociatedRevisions($workspace_id, $entity_type_id);
foreach (array_keys($associated_revisions) as $revision_id) {
if ($count > $batch_size) {
continue 2;
}
$associated_entity_storage
->deleteRevision($revision_id);
$count++;
}
$this->workspaceAssociation
->deleteAssociations($workspace_id, $entity_type_id, $entities);
}
if (!$this->workspaceAssociation
->getTrackedEntities($workspace_id)) {
unset($deleted_workspace_ids[$workspace_id]);
$this->state
->set('workspace.deleted', $deleted_workspace_ids);
}
}
}