annotate core/modules/workspaces/src/WorkspacePublisher.php @ 19:fa3358dc1485 tip

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