annotate core/modules/workspaces/src/WorkspacePublisher.php @ 5:12f9dff5fda9 tip

Update to Drupal core 8.7.1
author Chris Cannam
date Thu, 09 May 2019 15:34:47 +0100
parents a9cd425dd02b
children
rev   line source
Chris@4 1 <?php
Chris@4 2
Chris@4 3 namespace Drupal\workspaces;
Chris@4 4
Chris@4 5 use Drupal\Core\Database\Connection;
Chris@4 6 use Drupal\Core\Entity\EntityTypeManagerInterface;
Chris@4 7
Chris@4 8 /**
Chris@4 9 * Default implementation of the workspace publisher.
Chris@4 10 *
Chris@4 11 * @internal
Chris@4 12 */
Chris@4 13 class WorkspacePublisher implements WorkspacePublisherInterface {
Chris@4 14
Chris@4 15 /**
Chris@4 16 * The source workspace entity.
Chris@4 17 *
Chris@4 18 * @var \Drupal\workspaces\WorkspaceInterface
Chris@4 19 */
Chris@4 20 protected $sourceWorkspace;
Chris@4 21
Chris@4 22 /**
Chris@4 23 * The target workspace entity.
Chris@4 24 *
Chris@4 25 * @var \Drupal\workspaces\WorkspaceInterface
Chris@4 26 */
Chris@4 27 protected $targetWorkspace;
Chris@4 28
Chris@4 29 /**
Chris@4 30 * The entity type manager.
Chris@4 31 *
Chris@4 32 * @var \Drupal\Core\Entity\EntityTypeManagerInterface
Chris@4 33 */
Chris@4 34 protected $entityTypeManager;
Chris@4 35
Chris@4 36 /**
Chris@4 37 * The database connection.
Chris@4 38 *
Chris@4 39 * @var \Drupal\Core\Database\Connection
Chris@4 40 */
Chris@4 41 protected $database;
Chris@4 42
Chris@4 43 /**
Chris@4 44 * The workspace association storage.
Chris@4 45 *
Chris@4 46 * @var \Drupal\workspaces\WorkspaceAssociationStorageInterface
Chris@4 47 */
Chris@4 48 protected $workspaceAssociationStorage;
Chris@4 49
Chris@4 50 /**
Chris@5 51 * The workspace manager.
Chris@5 52 *
Chris@5 53 * @var \Drupal\workspaces\WorkspaceManagerInterface
Chris@5 54 */
Chris@5 55 protected $workspaceManager;
Chris@5 56
Chris@5 57 /**
Chris@4 58 * Constructs a new WorkspacePublisher.
Chris@4 59 *
Chris@4 60 * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
Chris@4 61 * The entity type manager.
Chris@4 62 * @param \Drupal\Core\Database\Connection $database
Chris@4 63 * Database connection.
Chris@5 64 * @param \Drupal\workspaces\WorkspaceManagerInterface $workspace_manager
Chris@5 65 * The workspace manager.
Chris@4 66 */
Chris@5 67 public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $database, WorkspaceManagerInterface $workspace_manager, WorkspaceInterface $source) {
Chris@4 68 $this->entityTypeManager = $entity_type_manager;
Chris@4 69 $this->database = $database;
Chris@4 70 $this->workspaceAssociationStorage = $entity_type_manager->getStorage('workspace_association');
Chris@5 71 $this->workspaceManager = $workspace_manager;
Chris@4 72 $this->sourceWorkspace = $source;
Chris@4 73 $this->targetWorkspace = $this->entityTypeManager->getStorage('workspace')->load(WorkspaceInterface::DEFAULT_WORKSPACE);
Chris@4 74 }
Chris@4 75
Chris@4 76 /**
Chris@4 77 * {@inheritdoc}
Chris@4 78 */
Chris@4 79 public function publish() {
Chris@4 80 if ($this->checkConflictsOnTarget()) {
Chris@4 81 throw new WorkspaceConflictException();
Chris@4 82 }
Chris@4 83
Chris@4 84 $transaction = $this->database->startTransaction();
Chris@4 85 try {
Chris@4 86 // @todo Handle the publishing of a workspace with a batch operation in
Chris@4 87 // https://www.drupal.org/node/2958752.
Chris@5 88 $this->workspaceManager->executeInWorkspace($this->targetWorkspace->id(), function () {
Chris@5 89 foreach ($this->getDifferringRevisionIdsOnSource() as $entity_type_id => $revision_difference) {
Chris@5 90
Chris@5 91 $entity_revisions = $this->entityTypeManager->getStorage($entity_type_id)
Chris@5 92 ->loadMultipleRevisions(array_keys($revision_difference));
Chris@5 93 $default_revisions = $this->entityTypeManager->getStorage($entity_type_id)
Chris@5 94 ->loadMultiple(array_values($revision_difference));
Chris@5 95
Chris@5 96 /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
Chris@5 97 foreach ($entity_revisions as $entity) {
Chris@5 98 // When pushing workspace-specific revisions to the default
Chris@5 99 // workspace (Live), we simply need to mark them as default
Chris@5 100 // revisions.
Chris@5 101 $entity->setSyncing(TRUE);
Chris@5 102 $entity->isDefaultRevision(TRUE);
Chris@5 103 $entity->original = $default_revisions[$entity->id()];
Chris@5 104 $entity->save();
Chris@5 105 }
Chris@4 106 }
Chris@5 107 });
Chris@4 108 }
Chris@4 109 catch (\Exception $e) {
Chris@4 110 $transaction->rollBack();
Chris@4 111 watchdog_exception('workspaces', $e);
Chris@4 112 throw $e;
Chris@4 113 }
Chris@4 114
Chris@4 115 // Notify the workspace association storage that a workspace has been
Chris@4 116 // pushed.
Chris@4 117 $this->workspaceAssociationStorage->postPush($this->sourceWorkspace);
Chris@4 118 }
Chris@4 119
Chris@4 120 /**
Chris@4 121 * {@inheritdoc}
Chris@4 122 */
Chris@4 123 public function getSourceLabel() {
Chris@4 124 return $this->sourceWorkspace->label();
Chris@4 125 }
Chris@4 126
Chris@4 127 /**
Chris@4 128 * {@inheritdoc}
Chris@4 129 */
Chris@4 130 public function getTargetLabel() {
Chris@4 131 return $this->targetWorkspace->label();
Chris@4 132 }
Chris@4 133
Chris@4 134 /**
Chris@4 135 * {@inheritdoc}
Chris@4 136 */
Chris@4 137 public function checkConflictsOnTarget() {
Chris@4 138 // Nothing to do for now, we can not get to a conflicting state because an
Chris@4 139 // entity which is being edited in a workspace can not be edited in any
Chris@4 140 // other workspace.
Chris@4 141 }
Chris@4 142
Chris@4 143 /**
Chris@4 144 * {@inheritdoc}
Chris@4 145 */
Chris@4 146 public function getDifferringRevisionIdsOnTarget() {
Chris@4 147 $target_revision_difference = [];
Chris@4 148
Chris@4 149 $tracked_entities = $this->workspaceAssociationStorage->getTrackedEntities($this->sourceWorkspace->id());
Chris@4 150 foreach ($tracked_entities as $entity_type_id => $tracked_revisions) {
Chris@4 151 $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
Chris@4 152
Chris@4 153 // Get the latest revision IDs for all the entities that are tracked by
Chris@4 154 // the source workspace.
Chris@4 155 $query = $this->entityTypeManager
Chris@4 156 ->getStorage($entity_type_id)
Chris@4 157 ->getQuery()
Chris@4 158 ->condition($entity_type->getKey('id'), $tracked_revisions, 'IN')
Chris@4 159 ->latestRevision();
Chris@4 160 $result = $query->execute();
Chris@4 161
Chris@4 162 // Now we compare the revision IDs which are tracked by the source
Chris@4 163 // workspace to the latest revision IDs of those entities and the
Chris@4 164 // difference between these two arrays gives us all the entities which
Chris@4 165 // have been modified on the target.
Chris@4 166 if ($revision_difference = array_diff_key($result, $tracked_revisions)) {
Chris@4 167 $target_revision_difference[$entity_type_id] = $revision_difference;
Chris@4 168 }
Chris@4 169 }
Chris@4 170
Chris@4 171 return $target_revision_difference;
Chris@4 172 }
Chris@4 173
Chris@4 174 /**
Chris@4 175 * {@inheritdoc}
Chris@4 176 */
Chris@4 177 public function getDifferringRevisionIdsOnSource() {
Chris@4 178 // Get the Workspace association revisions which haven't been pushed yet.
Chris@4 179 return $this->workspaceAssociationStorage->getTrackedEntities($this->sourceWorkspace->id());
Chris@4 180 }
Chris@4 181
Chris@4 182 /**
Chris@4 183 * {@inheritdoc}
Chris@4 184 */
Chris@4 185 public function getNumberOfChangesOnTarget() {
Chris@4 186 $total_changes = $this->getDifferringRevisionIdsOnTarget();
Chris@4 187 return count($total_changes, COUNT_RECURSIVE) - count($total_changes);
Chris@4 188 }
Chris@4 189
Chris@4 190 /**
Chris@4 191 * {@inheritdoc}
Chris@4 192 */
Chris@4 193 public function getNumberOfChangesOnSource() {
Chris@4 194 $total_changes = $this->getDifferringRevisionIdsOnSource();
Chris@4 195 return count($total_changes, COUNT_RECURSIVE) - count($total_changes);
Chris@4 196 }
Chris@4 197
Chris@4 198 }