Issue #3129762 by amateescu, adriancid, msuthars, Alexj12: Creating an unpublished entity in a workspace does not set the workspace field on the revision
parent
40d5e404a4
commit
cd12944d9a
|
@ -136,8 +136,10 @@ class EntityOperations implements ContainerInjectionInterface {
|
||||||
// become the default revision only when it is replicated to the default
|
// become the default revision only when it is replicated to the default
|
||||||
// workspace.
|
// workspace.
|
||||||
$entity->isDefaultRevision(FALSE);
|
$entity->isDefaultRevision(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
// Track the workspaces in which the new revision was saved.
|
// Track the workspaces in which the new revision was saved.
|
||||||
|
if (!$entity->isSyncing()) {
|
||||||
$field_name = $entity_type->getRevisionMetadataKey('workspace');
|
$field_name = $entity_type->getRevisionMetadataKey('workspace');
|
||||||
$entity->{$field_name}->target_id = $this->workspaceManager->getActiveWorkspace()->id();
|
$entity->{$field_name}->target_id = $this->workspaceManager->getActiveWorkspace()->id();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
namespace Drupal\workspaces\Plugin\Validation\Constraint;
|
namespace Drupal\workspaces\Plugin\Validation\Constraint;
|
||||||
|
|
||||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||||
use Drupal\workspaces\WorkspaceAssociationInterface;
|
use Drupal\Core\State\StateInterface;
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
use Symfony\Component\Validator\Constraint;
|
use Symfony\Component\Validator\Constraint;
|
||||||
use Symfony\Component\Validator\ConstraintValidator;
|
use Symfony\Component\Validator\ConstraintValidator;
|
||||||
|
@ -14,20 +14,20 @@ use Symfony\Component\Validator\ConstraintValidator;
|
||||||
class DeletedWorkspaceConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {
|
class DeletedWorkspaceConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The workspace association service.
|
* The state service.
|
||||||
*
|
*
|
||||||
* @var \Drupal\workspaces\WorkspaceAssociationInterface
|
* @var \Drupal\Core\State\StateInterface
|
||||||
*/
|
*/
|
||||||
protected $workspaceAssociation;
|
protected $state;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new DeletedWorkspaceConstraintValidator instance.
|
* Creates a new DeletedWorkspaceConstraintValidator instance.
|
||||||
*
|
*
|
||||||
* @param \Drupal\workspaces\WorkspaceAssociationInterface $workspace_association
|
* @param \Drupal\Core\State\StateInterface $state
|
||||||
* The workspace association service.
|
* The state service.
|
||||||
*/
|
*/
|
||||||
public function __construct(WorkspaceAssociationInterface $workspace_association) {
|
public function __construct(StateInterface $state) {
|
||||||
$this->workspaceAssociation = $workspace_association;
|
$this->state = $state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,7 +35,7 @@ class DeletedWorkspaceConstraintValidator extends ConstraintValidator implements
|
||||||
*/
|
*/
|
||||||
public static function create(ContainerInterface $container) {
|
public static function create(ContainerInterface $container) {
|
||||||
return new static(
|
return new static(
|
||||||
$container->get('workspaces.association')
|
$container->get('state')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,8 @@ class DeletedWorkspaceConstraintValidator extends ConstraintValidator implements
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->workspaceAssociation->getTrackedEntities($value->getEntity()->id())) {
|
$deleted_workspace_ids = $this->state->get('workspace.deleted', []);
|
||||||
|
if (isset($deleted_workspace_ids[$value->getEntity()->id()])) {
|
||||||
$this->context->addViolation($constraint->message);
|
$this->context->addViolation($constraint->message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,13 +186,21 @@ class WorkspaceAssociation implements WorkspaceAssociationInterface, EventSubscr
|
||||||
$id_field = $table_mapping->getColumnNames($entity_type->getKey('id'))['value'];
|
$id_field = $table_mapping->getColumnNames($entity_type->getKey('id'))['value'];
|
||||||
$revision_id_field = $table_mapping->getColumnNames($entity_type->getKey('revision'))['value'];
|
$revision_id_field = $table_mapping->getColumnNames($entity_type->getKey('revision'))['value'];
|
||||||
|
|
||||||
|
$workspace_tree = $this->workspaceRepository->loadTree();
|
||||||
|
if (isset($workspace_tree[$workspace_id])) {
|
||||||
|
$workspace_candidates = array_merge([$workspace_id], $workspace_tree[$workspace_id]['ancestors']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$workspace_candidates = [$workspace_id];
|
||||||
|
}
|
||||||
|
|
||||||
$query = $this->database->select($entity_type->getRevisionTable(), 'revision');
|
$query = $this->database->select($entity_type->getRevisionTable(), 'revision');
|
||||||
$query->leftJoin($entity_type->getBaseTable(), 'base', "[revision].[$id_field] = [base].[$id_field]");
|
$query->leftJoin($entity_type->getBaseTable(), 'base', "[revision].[$id_field] = [base].[$id_field]");
|
||||||
|
|
||||||
$query
|
$query
|
||||||
->fields('revision', [$revision_id_field, $id_field])
|
->fields('revision', [$revision_id_field, $id_field])
|
||||||
->condition("revision.$workspace_field", $workspace_id)
|
->condition("revision.$workspace_field", $workspace_candidates, 'IN')
|
||||||
->where("[revision].[$revision_id_field] > [base].[$revision_id_field]")
|
->where("[revision].[$revision_id_field] >= [base].[$revision_id_field]")
|
||||||
->orderBy("revision.$revision_id_field", 'ASC');
|
->orderBy("revision.$revision_id_field", 'ASC');
|
||||||
|
|
||||||
// Restrict the result to a set of entity ID's if provided.
|
// Restrict the result to a set of entity ID's if provided.
|
||||||
|
@ -203,6 +211,42 @@ class WorkspaceAssociation implements WorkspaceAssociationInterface, EventSubscr
|
||||||
return $query->execute()->fetchAllKeyed();
|
return $query->execute()->fetchAllKeyed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getAssociatedInitialRevisions(string $workspace_id, string $entity_type_id, array $entity_ids = []) {
|
||||||
|
/** @var \Drupal\Core\Entity\EntityStorageInterface $storage */
|
||||||
|
$storage = $this->entityTypeManager->getStorage($entity_type_id);
|
||||||
|
|
||||||
|
// If the entity type is not using core's default entity storage, we can't
|
||||||
|
// assume the table mapping layout so we have to return only the latest
|
||||||
|
// tracked revisions.
|
||||||
|
if (!$storage instanceof SqlContentEntityStorage) {
|
||||||
|
return $this->getTrackedEntities($workspace_id, $entity_type_id, $entity_ids)[$entity_type_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
$entity_type = $storage->getEntityType();
|
||||||
|
$table_mapping = $storage->getTableMapping();
|
||||||
|
$workspace_field = $table_mapping->getColumnNames($entity_type->get('revision_metadata_keys')['workspace'])['target_id'];
|
||||||
|
$id_field = $table_mapping->getColumnNames($entity_type->getKey('id'))['value'];
|
||||||
|
$revision_id_field = $table_mapping->getColumnNames($entity_type->getKey('revision'))['value'];
|
||||||
|
|
||||||
|
$query = $this->database->select($entity_type->getBaseTable(), 'base');
|
||||||
|
$query->leftJoin($entity_type->getRevisionTable(), 'revision', "[base].[$revision_id_field] = [revision].[$revision_id_field]");
|
||||||
|
|
||||||
|
$query
|
||||||
|
->fields('base', [$revision_id_field, $id_field])
|
||||||
|
->condition("revision.$workspace_field", $workspace_id, '=')
|
||||||
|
->orderBy("base.$revision_id_field", 'ASC');
|
||||||
|
|
||||||
|
// Restrict the result to a set of entity ID's if provided.
|
||||||
|
if ($entity_ids) {
|
||||||
|
$query->condition("base.$id_field", $entity_ids, 'IN');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->execute()->fetchAllKeyed();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -74,6 +74,23 @@ interface WorkspaceAssociationInterface {
|
||||||
*/
|
*/
|
||||||
public function getAssociatedRevisions($workspace_id, $entity_type_id, $entity_ids = NULL);
|
public function getAssociatedRevisions($workspace_id, $entity_type_id, $entity_ids = NULL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves all content revisions that were created in a given workspace.
|
||||||
|
*
|
||||||
|
* @param string $workspace_id
|
||||||
|
* The ID of the workspace.
|
||||||
|
* @param string $entity_type_id
|
||||||
|
* An entity type ID to find revisions for.
|
||||||
|
* @param int[]|string[] $entity_ids
|
||||||
|
* (optional) An array of entity IDs to filter the results by. Defaults to
|
||||||
|
* an empty array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* Returns an array where the values are an array of entity IDs keyed by
|
||||||
|
* revision IDs.
|
||||||
|
*/
|
||||||
|
public function getAssociatedInitialRevisions(string $workspace_id, string $entity_type_id, array $entity_ids = []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a list of workspace IDs in which an entity is tracked.
|
* Gets a list of workspace IDs in which an entity is tracked.
|
||||||
*
|
*
|
||||||
|
|
|
@ -316,31 +316,60 @@ class WorkspaceManager implements WorkspaceManagerInterface {
|
||||||
// Get the first deleted workspace from the list and delete the revisions
|
// Get the first deleted workspace from the list and delete the revisions
|
||||||
// associated with it, along with the workspace association records.
|
// associated with it, along with the workspace association records.
|
||||||
$workspace_id = reset($deleted_workspace_ids);
|
$workspace_id = reset($deleted_workspace_ids);
|
||||||
$tracked_entities = $this->workspaceAssociation->getTrackedEntities($workspace_id);
|
|
||||||
|
$all_associated_revisions = [];
|
||||||
|
foreach (array_keys($this->getSupportedEntityTypes()) as $entity_type_id) {
|
||||||
|
$all_associated_revisions[$entity_type_id] = $this->workspaceAssociation->getAssociatedRevisions($workspace_id, $entity_type_id);
|
||||||
|
}
|
||||||
|
$all_associated_revisions = array_filter($all_associated_revisions);
|
||||||
|
|
||||||
$count = 1;
|
$count = 1;
|
||||||
foreach ($tracked_entities as $entity_type_id => $entities) {
|
foreach ($all_associated_revisions as $entity_type_id => $associated_revisions) {
|
||||||
$associated_entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
|
$associated_entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
|
||||||
$associated_revisions = $this->workspaceAssociation->getAssociatedRevisions($workspace_id, $entity_type_id);
|
|
||||||
|
// Sort the associated revisions in reverse ID order, so we can delete the
|
||||||
|
// most recent revisions first.
|
||||||
|
krsort($associated_revisions);
|
||||||
|
|
||||||
|
// Get a list of default revisions tracked by the given workspace, because
|
||||||
|
// they need to be handled differently than pending revisions.
|
||||||
|
$initial_revision_ids = $this->workspaceAssociation->getAssociatedInitialRevisions($workspace_id, $entity_type_id);
|
||||||
|
|
||||||
foreach (array_keys($associated_revisions) as $revision_id) {
|
foreach (array_keys($associated_revisions) as $revision_id) {
|
||||||
if ($count > $batch_size) {
|
if ($count > $batch_size) {
|
||||||
continue 2;
|
continue 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the associated entity revision.
|
// If the workspace is tracking the entity's default revision (i.e. the
|
||||||
$associated_entity_storage->deleteRevision($revision_id);
|
// entity was created inside that workspace), we need to delete the
|
||||||
|
// whole entity after all of its pending revisions are gone.
|
||||||
|
if (isset($initial_revision_ids[$revision_id])) {
|
||||||
|
$associated_entity_storage->delete([$associated_entity_storage->load($initial_revision_ids[$revision_id])]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Delete the associated entity revision.
|
||||||
|
$associated_entity_storage->deleteRevision($revision_id);
|
||||||
|
}
|
||||||
$count++;
|
$count++;
|
||||||
}
|
}
|
||||||
// Delete the workspace association entries.
|
|
||||||
$this->workspaceAssociation->deleteAssociations($workspace_id, $entity_type_id, $entities);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The purging operation above might have taken a long time, so we need to
|
// The purging operation above might have taken a long time, so we need to
|
||||||
// request a fresh list of tracked entities. If it is empty, we can go ahead
|
// request a fresh list of tracked entities. If it is empty, we can go ahead
|
||||||
// and remove the deleted workspace ID entry from state.
|
// and remove the deleted workspace ID entry from state.
|
||||||
if (!$this->workspaceAssociation->getTrackedEntities($workspace_id)) {
|
$has_associated_revisions = FALSE;
|
||||||
|
foreach (array_keys($this->getSupportedEntityTypes()) as $entity_type_id) {
|
||||||
|
if (!empty($this->workspaceAssociation->getAssociatedRevisions($workspace_id, $entity_type_id))) {
|
||||||
|
$has_associated_revisions = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$has_associated_revisions) {
|
||||||
unset($deleted_workspace_ids[$workspace_id]);
|
unset($deleted_workspace_ids[$workspace_id]);
|
||||||
$this->state->set('workspace.deleted', $deleted_workspace_ids);
|
$this->state->set('workspace.deleted', $deleted_workspace_ids);
|
||||||
|
|
||||||
|
// Delete any possible leftover association entries.
|
||||||
|
$this->workspaceAssociation->deleteAssociations($workspace_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -145,6 +145,7 @@ class WorkspaceRepository implements WorkspaceRepositoryInterface {
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function resetCache() {
|
public function resetCache() {
|
||||||
|
$this->cache->invalidate('workspace_tree');
|
||||||
$this->tree = NULL;
|
$this->tree = NULL;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\Tests\workspaces\Kernel;
|
||||||
|
|
||||||
|
use Drupal\KernelTests\KernelTestBase;
|
||||||
|
use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
|
||||||
|
use Drupal\Tests\node\Traits\NodeCreationTrait;
|
||||||
|
use Drupal\Tests\user\Traits\UserCreationTrait;
|
||||||
|
use Drupal\workspaces\Entity\Workspace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests workspace associations.
|
||||||
|
*
|
||||||
|
* @coversDefaultClass \Drupal\workspaces\WorkspaceAssociation
|
||||||
|
*
|
||||||
|
* @group workspaces
|
||||||
|
*/
|
||||||
|
class WorkspaceAssociationTest extends KernelTestBase {
|
||||||
|
|
||||||
|
use ContentTypeCreationTrait;
|
||||||
|
use NodeCreationTrait;
|
||||||
|
use UserCreationTrait;
|
||||||
|
use WorkspaceTestTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The entity type manager.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||||
|
*/
|
||||||
|
protected $entityTypeManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected static $modules = [
|
||||||
|
'field',
|
||||||
|
'filter',
|
||||||
|
'node',
|
||||||
|
'text',
|
||||||
|
'user',
|
||||||
|
'system',
|
||||||
|
'path_alias',
|
||||||
|
'workspaces',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function setUp(): void {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->entityTypeManager = \Drupal::entityTypeManager();
|
||||||
|
|
||||||
|
$this->installEntitySchema('node');
|
||||||
|
$this->installEntitySchema('user');
|
||||||
|
$this->installEntitySchema('workspace');
|
||||||
|
|
||||||
|
$this->installConfig(['filter', 'node', 'system']);
|
||||||
|
|
||||||
|
$this->installSchema('node', ['node_access']);
|
||||||
|
$this->installSchema('system', ['sequences']);
|
||||||
|
$this->installSchema('workspaces', ['workspace_association']);
|
||||||
|
|
||||||
|
$this->createContentType(['type' => 'article']);
|
||||||
|
|
||||||
|
$permissions = array_intersect([
|
||||||
|
'administer nodes',
|
||||||
|
'create workspace',
|
||||||
|
'edit any workspace',
|
||||||
|
'view any workspace',
|
||||||
|
], array_keys($this->container->get('user.permissions')->getPermissions()));
|
||||||
|
$this->setCurrentUser($this->createUser($permissions));
|
||||||
|
|
||||||
|
$this->workspaces['stage'] = Workspace::create(['id' => 'stage', 'label' => 'Stage']);
|
||||||
|
$this->workspaces['stage']->save();
|
||||||
|
$this->workspaces['dev'] = Workspace::create(['id' => 'dev', 'parent' => 'stage', 'label' => 'Dev']);
|
||||||
|
$this->workspaces['dev']->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the revisions tracked by a workspace.
|
||||||
|
*
|
||||||
|
* @covers ::getTrackedEntities
|
||||||
|
* @covers ::getAssociatedRevisions
|
||||||
|
*/
|
||||||
|
public function testWorkspaceAssociation() {
|
||||||
|
$this->createNode(['title' => 'Test article 1 - live - unpublished', 'type' => 'article', 'status' => 0]);
|
||||||
|
$this->createNode(['title' => 'Test article 2 - live - published', 'type' => 'article']);
|
||||||
|
|
||||||
|
// Edit one of the existing nodes in 'stage'.
|
||||||
|
$this->switchToWorkspace('stage');
|
||||||
|
$node = $this->entityTypeManager->getStorage('node')->load(1);
|
||||||
|
$node->setTitle('Test article 1 - stage - published');
|
||||||
|
$node->setPublished();
|
||||||
|
// This creates rev. 3.
|
||||||
|
$node->save();
|
||||||
|
|
||||||
|
// Generate content with the following structure:
|
||||||
|
// Stage:
|
||||||
|
// - Test article 3 - stage - unpublished (rev. 4)
|
||||||
|
// - Test article 4 - stage - published (rev. 5 and 6)
|
||||||
|
$this->createNode(['title' => 'Test article 3 - stage - unpublished', 'type' => 'article', 'status' => 0]);
|
||||||
|
$this->createNode(['title' => 'Test article 4 - stage - published', 'type' => 'article']);
|
||||||
|
|
||||||
|
$expected_latest_revisions = [
|
||||||
|
'stage' => [3, 4, 6],
|
||||||
|
];
|
||||||
|
$expected_all_revisions = [
|
||||||
|
'stage' => [3, 4, 5, 6],
|
||||||
|
];
|
||||||
|
$expected_initial_revisions = [
|
||||||
|
'stage' => [4, 5],
|
||||||
|
];
|
||||||
|
$this->assertWorkspaceAssociations('node', $expected_latest_revisions, $expected_all_revisions, $expected_initial_revisions);
|
||||||
|
|
||||||
|
// Dev:
|
||||||
|
// - Test article 1 - stage - published (rev. 3)
|
||||||
|
// - Test article 3 - stage - unpublished (rev. 4)
|
||||||
|
// - Test article 4 - stage - published (rev. 5 and 6)
|
||||||
|
// - Test article 5 - dev - unpublished (rev. 7)
|
||||||
|
// - Test article 6 - dev - published (rev. 8 and 9)
|
||||||
|
$this->switchToWorkspace('dev');
|
||||||
|
$this->createNode(['title' => 'Test article 5 - dev - unpublished', 'type' => 'article', 'status' => 0]);
|
||||||
|
$this->createNode(['title' => 'Test article 6 - dev - published', 'type' => 'article']);
|
||||||
|
|
||||||
|
$expected_latest_revisions += [
|
||||||
|
'dev' => [3, 4, 6, 7, 9],
|
||||||
|
];
|
||||||
|
// Revisions 3, 4, 5 and 6 that were created in the parent 'stage' workspace
|
||||||
|
// are also considered as being part of the child 'dev' workspace.
|
||||||
|
$expected_all_revisions += [
|
||||||
|
'dev' => [3, 4, 5, 6, 7, 8, 9],
|
||||||
|
];
|
||||||
|
$expected_initial_revisions += [
|
||||||
|
'stage' => [7, 8],
|
||||||
|
];
|
||||||
|
$this->assertWorkspaceAssociations('node', $expected_latest_revisions, $expected_all_revisions, $expected_initial_revisions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the workspace associations for a test scenario.
|
||||||
|
*
|
||||||
|
* @param string $entity_type_id
|
||||||
|
* The ID of the entity type that is being tested.
|
||||||
|
* @param array $expected_latest_revisions
|
||||||
|
* An array of expected values for the latest tracked revisions.
|
||||||
|
* @param array $expected_all_revisions
|
||||||
|
* An array of expected values for all the tracked revisions.
|
||||||
|
* @param array $expected_initial_revisions
|
||||||
|
* An array of expected values for the initial revisions, i.e. for the
|
||||||
|
* entities that were created in the specified workspace.
|
||||||
|
*/
|
||||||
|
protected function assertWorkspaceAssociations($entity_type_id, array $expected_latest_revisions, array $expected_all_revisions, array $expected_initial_revisions) {
|
||||||
|
$workspace_association = \Drupal::service('workspaces.association');
|
||||||
|
foreach ($expected_latest_revisions as $workspace_id => $expected_tracked_revision_ids) {
|
||||||
|
$tracked_entities = $workspace_association->getTrackedEntities($workspace_id, $entity_type_id);
|
||||||
|
$tracked_revision_ids = $tracked_entities[$entity_type_id] ?? [];
|
||||||
|
$this->assertEquals($expected_tracked_revision_ids, array_keys($tracked_revision_ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($expected_all_revisions as $workspace_id => $expected_all_revision_ids) {
|
||||||
|
$all_associated_revisions = $workspace_association->getAssociatedRevisions($workspace_id, $entity_type_id);
|
||||||
|
$this->assertEquals($expected_all_revision_ids, array_keys($all_associated_revisions));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($expected_initial_revisions as $workspace_id => $expected_initial_revision_ids) {
|
||||||
|
$initial_revisions = $workspace_association->getAssociatedInitialRevisions($workspace_id, $entity_type_id);
|
||||||
|
$this->assertEquals($expected_initial_revision_ids, array_keys($initial_revisions));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -69,6 +69,7 @@ class WorkspaceCRUDTest extends KernelTestBase {
|
||||||
$this->installEntitySchema('workspace');
|
$this->installEntitySchema('workspace');
|
||||||
$this->installSchema('workspaces', ['workspace_association']);
|
$this->installSchema('workspaces', ['workspace_association']);
|
||||||
$this->installEntitySchema('node');
|
$this->installEntitySchema('node');
|
||||||
|
$this->installEntitySchema('path_alias');
|
||||||
|
|
||||||
$this->installConfig(['filter', 'node', 'system']);
|
$this->installConfig(['filter', 'node', 'system']);
|
||||||
|
|
||||||
|
@ -106,10 +107,9 @@ class WorkspaceCRUDTest extends KernelTestBase {
|
||||||
$workspace_1_node_1 = $this->createNode(['status' => FALSE]);
|
$workspace_1_node_1 = $this->createNode(['status' => FALSE]);
|
||||||
$workspace_1_node_2 = $this->createNode(['status' => FALSE]);
|
$workspace_1_node_2 = $this->createNode(['status' => FALSE]);
|
||||||
|
|
||||||
// The 'live' workspace should have 2 revisions now. The initial revision
|
// Check that the workspace tracks the initial revisions for both nodes.
|
||||||
// for each node.
|
$initial_revisions = $workspace_association->getAssociatedInitialRevisions($workspace_1->id(), 'node');
|
||||||
$live_revisions = $this->getUnassociatedRevisions('node');
|
$this->assertCount(2, $initial_revisions);
|
||||||
$this->assertCount(2, $live_revisions);
|
|
||||||
|
|
||||||
for ($i = 0; $i < 4; $i++) {
|
for ($i = 0; $i < 4; $i++) {
|
||||||
$workspace_1_node_1->setNewRevision(TRUE);
|
$workspace_1_node_1->setNewRevision(TRUE);
|
||||||
|
@ -123,13 +123,10 @@ class WorkspaceCRUDTest extends KernelTestBase {
|
||||||
$tracked_entities = $workspace_association->getTrackedEntities($workspace_1->id());
|
$tracked_entities = $workspace_association->getTrackedEntities($workspace_1->id());
|
||||||
$this->assertCount(2, $tracked_entities['node']);
|
$this->assertCount(2, $tracked_entities['node']);
|
||||||
|
|
||||||
// There should still be 2 revisions associated with 'live'.
|
// Since all the revisions were created inside a workspace, including the
|
||||||
$live_revisions = $this->getUnassociatedRevisions('node');
|
// default one, 'workspace_1' should be tracking all 10 revisions.
|
||||||
$this->assertCount(2, $live_revisions);
|
|
||||||
|
|
||||||
// The other 8 revisions should be associated with 'workspace_1'.
|
|
||||||
$associated_revisions = $workspace_association->getAssociatedRevisions($workspace_1->id(), 'node');
|
$associated_revisions = $workspace_association->getAssociatedRevisions($workspace_1->id(), 'node');
|
||||||
$this->assertCount(8, $associated_revisions);
|
$this->assertCount(10, $associated_revisions);
|
||||||
|
|
||||||
// Check that we are allowed to delete the workspace.
|
// Check that we are allowed to delete the workspace.
|
||||||
$this->assertTrue($workspace_1->access('delete', $admin));
|
$this->assertTrue($workspace_1->access('delete', $admin));
|
||||||
|
@ -146,10 +143,6 @@ class WorkspaceCRUDTest extends KernelTestBase {
|
||||||
$associated_revisions = $workspace_association->getAssociatedRevisions($workspace_1->id(), 'node');
|
$associated_revisions = $workspace_association->getAssociatedRevisions($workspace_1->id(), 'node');
|
||||||
$this->assertCount(0, $associated_revisions);
|
$this->assertCount(0, $associated_revisions);
|
||||||
|
|
||||||
// There should still be 2 revisions associated with 'live'.
|
|
||||||
$live_revisions = $this->getUnassociatedRevisions('node');
|
|
||||||
$this->assertCount(2, $live_revisions);
|
|
||||||
|
|
||||||
// Create another workspace, this time with a larger number of associated
|
// Create another workspace, this time with a larger number of associated
|
||||||
// node revisions so we can test the batch purge process.
|
// node revisions so we can test the batch purge process.
|
||||||
$workspace_2 = Workspace::create([
|
$workspace_2 = Workspace::create([
|
||||||
|
@ -169,23 +162,15 @@ class WorkspaceCRUDTest extends KernelTestBase {
|
||||||
$tracked_entities = $workspace_association->getTrackedEntities($workspace_2->id());
|
$tracked_entities = $workspace_association->getTrackedEntities($workspace_2->id());
|
||||||
$this->assertCount(1, $tracked_entities['node']);
|
$this->assertCount(1, $tracked_entities['node']);
|
||||||
|
|
||||||
// One revision of this entity is in 'live'.
|
// All 60 are associated with 'workspace_2'.
|
||||||
$live_revisions = $this->getUnassociatedRevisions('node', [$workspace_2_node_1->id()]);
|
|
||||||
$this->assertCount(1, $live_revisions);
|
|
||||||
|
|
||||||
// The other 59 are associated with 'workspace_2'.
|
|
||||||
$associated_revisions = $workspace_association->getAssociatedRevisions($workspace_2->id(), 'node', [$workspace_2_node_1->id()]);
|
$associated_revisions = $workspace_association->getAssociatedRevisions($workspace_2->id(), 'node', [$workspace_2_node_1->id()]);
|
||||||
$this->assertCount(59, $associated_revisions);
|
$this->assertCount(60, $associated_revisions);
|
||||||
|
|
||||||
// Delete the workspace and check that we still have 9 revision left to
|
// Delete the workspace and check that we still have 10 revision left to
|
||||||
// delete.
|
// delete.
|
||||||
$workspace_2->delete();
|
$workspace_2->delete();
|
||||||
$associated_revisions = $workspace_association->getAssociatedRevisions($workspace_2->id(), 'node', [$workspace_2_node_1->id()]);
|
$associated_revisions = $workspace_association->getAssociatedRevisions($workspace_2->id(), 'node', [$workspace_2_node_1->id()]);
|
||||||
$this->assertCount(9, $associated_revisions);
|
$this->assertCount(10, $associated_revisions);
|
||||||
|
|
||||||
// The live revision is also still there.
|
|
||||||
$live_revisions = $this->getUnassociatedRevisions('node', [$workspace_2_node_1->id()]);
|
|
||||||
$this->assertCount(1, $live_revisions);
|
|
||||||
|
|
||||||
$workspace_deleted = \Drupal::state()->get('workspace.deleted');
|
$workspace_deleted = \Drupal::state()->get('workspace.deleted');
|
||||||
$this->assertCount(1, $workspace_deleted);
|
$this->assertCount(1, $workspace_deleted);
|
||||||
|
@ -204,18 +189,11 @@ class WorkspaceCRUDTest extends KernelTestBase {
|
||||||
// from the "workspace.delete" state entry.
|
// from the "workspace.delete" state entry.
|
||||||
\Drupal::service('cron')->run();
|
\Drupal::service('cron')->run();
|
||||||
|
|
||||||
$associated_revisions = $workspace_association->getTrackedEntities($workspace_2->id());
|
|
||||||
$this->assertCount(0, $associated_revisions);
|
|
||||||
|
|
||||||
// 'workspace_2 'is empty now.
|
// 'workspace_2 'is empty now.
|
||||||
$associated_revisions = $workspace_association->getAssociatedRevisions($workspace_2->id(), 'node', [$workspace_2_node_1->id()]);
|
$associated_revisions = $workspace_association->getAssociatedRevisions($workspace_2->id(), 'node', [$workspace_2_node_1->id()]);
|
||||||
$this->assertCount(0, $associated_revisions);
|
$this->assertCount(0, $associated_revisions);
|
||||||
$tracked_entities = $workspace_association->getTrackedEntities($workspace_2->id());
|
$tracked_entities = $workspace_association->getTrackedEntities($workspace_2->id());
|
||||||
$this->assertEmpty($tracked_entities);
|
$this->assertCount(0, $tracked_entities);
|
||||||
|
|
||||||
// The 3 revisions in 'live' remain.
|
|
||||||
$live_revisions = $this->getUnassociatedRevisions('node');
|
|
||||||
$this->assertCount(3, $live_revisions);
|
|
||||||
|
|
||||||
$workspace_deleted = \Drupal::state()->get('workspace.deleted');
|
$workspace_deleted = \Drupal::state()->get('workspace.deleted');
|
||||||
$this->assertCount(0, $workspace_deleted);
|
$this->assertCount(0, $workspace_deleted);
|
||||||
|
|
|
@ -37,6 +37,12 @@ trait WorkspaceTestTrait {
|
||||||
$this->installEntitySchema('workspace');
|
$this->installEntitySchema('workspace');
|
||||||
$this->installSchema('workspaces', ['workspace_association']);
|
$this->installSchema('workspaces', ['workspace_association']);
|
||||||
|
|
||||||
|
// Install the entity schema for supported entity types to ensure that the
|
||||||
|
// 'workspace' revision metadata field gets created.
|
||||||
|
foreach (array_keys($this->workspaceManager->getSupportedEntityTypes()) as $entity_type_id) {
|
||||||
|
$this->installEntitySchema($entity_type_id);
|
||||||
|
}
|
||||||
|
|
||||||
// Create two workspaces by default, 'live' and 'stage'.
|
// Create two workspaces by default, 'live' and 'stage'.
|
||||||
$this->workspaces['live'] = Workspace::create(['id' => 'live', 'label' => 'Live']);
|
$this->workspaces['live'] = Workspace::create(['id' => 'live', 'label' => 'Live']);
|
||||||
$this->workspaces['live']->save();
|
$this->workspaces['live']->save();
|
||||||
|
|
Loading…
Reference in New Issue