Mercurial > hg > isophonics-drupal-site
diff core/modules/workspaces/src/WorkspacePublisher.php @ 17:129ea1e6d783
Update, including to Drupal core 8.6.10
author | Chris Cannam |
---|---|
date | Thu, 28 Feb 2019 13:21:36 +0000 |
parents | |
children | af1871eacc83 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/modules/workspaces/src/WorkspacePublisher.php Thu Feb 28 13:21:36 2019 +0000 @@ -0,0 +1,183 @@ +<?php + +namespace Drupal\workspaces; + +use Drupal\Core\Database\Connection; +use Drupal\Core\Entity\EntityTypeManagerInterface; + +/** + * Default implementation of the workspace publisher. + * + * @internal + */ +class WorkspacePublisher implements WorkspacePublisherInterface { + + /** + * The source workspace entity. + * + * @var \Drupal\workspaces\WorkspaceInterface + */ + protected $sourceWorkspace; + + /** + * The target workspace entity. + * + * @var \Drupal\workspaces\WorkspaceInterface + */ + protected $targetWorkspace; + + /** + * The entity type manager. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + + /** + * The database connection. + * + * @var \Drupal\Core\Database\Connection + */ + protected $database; + + /** + * The workspace association storage. + * + * @var \Drupal\workspaces\WorkspaceAssociationStorageInterface + */ + protected $workspaceAssociationStorage; + + /** + * Constructs a new WorkspacePublisher. + * + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager. + * @param \Drupal\Core\Database\Connection $database + * Database connection. + */ + public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $database, WorkspaceInterface $source) { + $this->entityTypeManager = $entity_type_manager; + $this->database = $database; + $this->workspaceAssociationStorage = $entity_type_manager->getStorage('workspace_association'); + $this->sourceWorkspace = $source; + $this->targetWorkspace = $this->entityTypeManager->getStorage('workspace')->load(WorkspaceInterface::DEFAULT_WORKSPACE); + } + + /** + * {@inheritdoc} + */ + public function publish() { + if ($this->checkConflictsOnTarget()) { + throw new WorkspaceConflictException(); + } + + $transaction = $this->database->startTransaction(); + try { + // @todo Handle the publishing of a workspace with a batch operation in + // https://www.drupal.org/node/2958752. + foreach ($this->getDifferringRevisionIdsOnSource() as $entity_type_id => $revision_difference) { + $entity_revisions = $this->entityTypeManager->getStorage($entity_type_id) + ->loadMultipleRevisions(array_keys($revision_difference)); + /** @var \Drupal\Core\Entity\EntityInterface|\Drupal\Core\Entity\RevisionableInterface $entity */ + foreach ($entity_revisions as $entity) { + // When pushing workspace-specific revisions to the default workspace + // (Live), we simply need to mark them as default revisions. + // @todo Remove this dynamic property once we have an API for + // associating temporary data with an entity: + // https://www.drupal.org/node/2896474. + $entity->_isReplicating = TRUE; + $entity->isDefaultRevision(TRUE); + $entity->save(); + } + } + } + catch (\Exception $e) { + $transaction->rollBack(); + watchdog_exception('workspaces', $e); + throw $e; + } + + // Notify the workspace association storage that a workspace has been + // pushed. + $this->workspaceAssociationStorage->postPush($this->sourceWorkspace); + } + + /** + * {@inheritdoc} + */ + public function getSourceLabel() { + return $this->sourceWorkspace->label(); + } + + /** + * {@inheritdoc} + */ + public function getTargetLabel() { + return $this->targetWorkspace->label(); + } + + /** + * {@inheritdoc} + */ + public function checkConflictsOnTarget() { + // Nothing to do for now, we can not get to a conflicting state because an + // entity which is being edited in a workspace can not be edited in any + // other workspace. + } + + /** + * {@inheritdoc} + */ + public function getDifferringRevisionIdsOnTarget() { + $target_revision_difference = []; + + $tracked_entities = $this->workspaceAssociationStorage->getTrackedEntities($this->sourceWorkspace->id()); + foreach ($tracked_entities as $entity_type_id => $tracked_revisions) { + $entity_type = $this->entityTypeManager->getDefinition($entity_type_id); + + // Get the latest revision IDs for all the entities that are tracked by + // the source workspace. + $query = $this->entityTypeManager + ->getStorage($entity_type_id) + ->getQuery() + ->condition($entity_type->getKey('id'), $tracked_revisions, 'IN') + ->latestRevision(); + $result = $query->execute(); + + // Now we compare the revision IDs which are tracked by the source + // workspace to the latest revision IDs of those entities and the + // difference between these two arrays gives us all the entities which + // have been modified on the target. + if ($revision_difference = array_diff_key($result, $tracked_revisions)) { + $target_revision_difference[$entity_type_id] = $revision_difference; + } + } + + return $target_revision_difference; + } + + /** + * {@inheritdoc} + */ + public function getDifferringRevisionIdsOnSource() { + // Get the Workspace association revisions which haven't been pushed yet. + return $this->workspaceAssociationStorage->getTrackedEntities($this->sourceWorkspace->id()); + } + + /** + * {@inheritdoc} + */ + public function getNumberOfChangesOnTarget() { + $total_changes = $this->getDifferringRevisionIdsOnTarget(); + return count($total_changes, COUNT_RECURSIVE) - count($total_changes); + } + + /** + * {@inheritdoc} + */ + public function getNumberOfChangesOnSource() { + $total_changes = $this->getDifferringRevisionIdsOnSource(); + return count($total_changes, COUNT_RECURSIVE) - count($total_changes); + } + +}