View source
<?php
namespace Drupal\multiversion\Entity\Storage;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\file\FileInterface;
use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
use Drupal\entity_reference_revisions\EntityReferenceRevisionsFieldItemList;
use Drupal\path\Plugin\Field\FieldType\PathFieldItemList;
use Drupal\pathauto\PathautoState;
use Drupal\workspaces\Entity\Workspace;
use Drupal\workspaces\WorkspaceInterface;
trait ContentEntityStorageTrait {
protected $isDeleted = FALSE;
protected $workspaceId = NULL;
protected $originalStorage;
public function getQueryServiceName() {
return 'multiversion.entity.query.sql';
}
public function getOriginalStorage() {
if ($this->originalStorage == NULL) {
$this->originalStorage = $this->entityManager
->getHandler($this->entityTypeId, 'original_storage');
}
return $this->originalStorage;
}
protected function buildQuery($ids, $revision_ids = FALSE) {
$query = parent::buildQuery($ids, $revision_ids);
if (!is_subclass_of($this->entityType
->getStorageClass(), ContentEntityStorageInterface::class)) {
return $query;
}
$revision_data_alias = 'revision';
if ($this->entityType
->isTranslatable()) {
$field_data_table = $this
->getDataTable();
$field_data_alias = 'field_data';
$query
->join($field_data_table, $field_data_alias, "{$field_data_alias}.{$this->idKey} = base.{$this->idKey}");
$revision_data_table = $this
->getRevisionDataTable();
$revision_data_alias = 'revision_data';
if ($revision_ids) {
$query
->join($revision_data_table, $revision_data_alias, "{$revision_data_alias}.{$this->revisionKey} = revision.{$this->revisionKey} AND {$revision_data_alias}.{$this->revisionKey} IN (:revisionIds[])", [
':revisionIds[]' => (array) $revision_ids,
]);
}
else {
$query
->join($revision_data_table, $revision_data_alias, "{$revision_data_alias}.{$this->revisionKey} = revision.{$this->revisionKey}");
}
}
$workspace = Workspace::load($this
->getWorkspaceId());
if (!$workspace
->isDefaultWorkspace()) {
$query
->addMetaData('active_workspace_id', $workspace
->id());
$query
->addMetaData('simple_query', FALSE);
$workspace_association_table = 'workspace_association';
$query
->leftJoin($workspace_association_table, $workspace_association_table, "%alias.target_entity_type_id = '{$this->entityTypeId}' AND %alias.target_entity_id = base.{$this->idKey}");
$query
->condition($query
->orConditionGroup()
->condition("{$workspace_association_table}.workspace", $workspace
->id())
->condition("{$workspace_association_table}.workspace", NULL, 'IS'));
}
if (!$revision_ids) {
$query
->condition("{$revision_data_alias}._deleted", (int) $this->isDeleted);
}
return $query;
}
public function useWorkspace($id) {
$this->workspaceId = $id;
return $this;
}
protected function getWorkspaceId() {
return $this->workspaceId ?: \Drupal::service('workspaces.manager')
->getActiveWorkspace()
->id();
}
public function loadUnchanged($id) {
$this
->resetCache([
$id,
]);
return $this
->load($id) ?: $this
->loadDeleted($id);
}
public function loadMultiple(array $ids = NULL) {
$this->isDeleted = FALSE;
return parent::loadMultiple($ids);
}
public function loadByProperties(array $values = []) {
$entity_query = $this
->getQuery();
$entity_query
->useWorkspace($this
->getWorkspaceId());
$entity_query
->accessCheck(FALSE);
$this
->buildPropertyQuery($entity_query, $values);
$result = $entity_query
->execute();
return $result ? $this
->loadMultiple($result) : [];
}
public function loadDeleted($id) {
$entities = $this
->loadMultipleDeleted([
$id,
]);
return isset($entities[$id]) ? $entities[$id] : NULL;
}
public function loadMultipleDeleted(array $ids = NULL) {
$this->isDeleted = TRUE;
return parent::loadMultiple($ids);
}
public function saveWithoutForcingNewRevision(EntityInterface $entity) {
$this
->getOriginalStorage()
->save($entity);
}
public function save(EntityInterface $entity) {
if (isset($entity->default_content)) {
list(, $hash) = explode('-', $entity->_rev->value);
$entity->_rev->revisions = [
$hash,
];
$entity->_rev->new_edit = FALSE;
}
$entity
->setNewRevision();
$branch = $this
->buildRevisionBranch($entity);
$local = (bool) $this->entityType
->get('local');
if (!$local) {
$this
->indexEntityRevision($entity);
$this
->indexEntityRevisionTree($entity, $branch);
}
if ($entity instanceof FileInterface) {
multiversion_prepare_file_destination($entity
->getFileUri());
}
if ($entity->_rev->is_stub && isset($entity->path->pathauto)) {
$entity->path->pathauto = PathautoState::SKIP;
}
foreach ($entity
->getFields() as $name => $field) {
if ($field instanceof EntityReferenceFieldItemListInterface && !$field instanceof EntityReferenceRevisionsFieldItemList) {
$value = [];
foreach ($field
->getValue() as $delta => $item) {
$value[$delta] = $item;
if ($item['target_id'] === NULL && isset($item['entity']) && $item['entity']->_rev->is_stub) {
$target_entities = $this
->loadByProperties([
'uuid' => $item["entity"]
->uuid(),
]);
if (!empty($target_entities)) {
$target_entity = reset($target_entities);
$item['target_id'] = $target_entity
->id();
unset($item['entity']);
$value[$delta] = $item;
}
}
}
if (!empty($value)) {
$field
->setValue($value, FALSE);
}
}
}
try {
$workspaces_manager = \Drupal::service('workspaces.manager');
if ($local) {
$save_result = $workspaces_manager
->executeInWorkspace(WorkspaceInterface::DEFAULT_WORKSPACE, function () use ($entity) {
return parent::save($entity);
});
}
else {
$save_result = parent::save($entity);
}
$this
->indexEntity($entity);
if (!$local) {
$this
->indexEntitySequence($entity);
$this
->indexEntityRevision($entity);
$this
->trackConflicts($entity);
}
return $save_result;
} catch (\Exception $e) {
$entity->_rev->new_edit = FALSE;
throw new EntityStorageException($e
->getMessage(), $e
->getCode(), $e);
}
}
protected function doPreSave(EntityInterface $entity) {
if (!$entity
->isNew() && !isset($entity->original)) {
$entity->original = $this
->loadUnchanged($entity->originalId ?: $entity
->id());
}
parent::doPreSave($entity);
}
protected function doPostSave(EntityInterface $entity, $update) {
parent::doPostSave($entity, $update);
$entity->originalId = $entity
->id();
if ($entity->_deleted->value == TRUE && isset($entity->path) && $entity->path instanceof PathFieldItemList) {
$entity->path
->delete();
}
}
protected function indexEntity(EntityInterface $entity) {
$workspace = Workspace::load($this
->getWorkspaceId());
$index_factory = \Drupal::service('multiversion.entity_index.factory');
$index_factory
->get('multiversion.entity_index.id', $workspace)
->add($entity);
$index_factory
->get('multiversion.entity_index.uuid', $workspace)
->add($entity);
}
protected function indexEntitySequence(EntityInterface $entity) {
$workspace = Workspace::load($this
->getWorkspaceId());
\Drupal::service('multiversion.entity_index.factory')
->get('multiversion.entity_index.sequence', $workspace)
->add($entity);
}
protected function indexEntityRevision(EntityInterface $entity) {
$workspace = Workspace::load($this
->getWorkspaceId());
\Drupal::service('multiversion.entity_index.factory')
->get('multiversion.entity_index.rev', $workspace)
->add($entity);
}
protected function indexEntityRevisionTree(EntityInterface $entity, $branch) {
$workspace = Workspace::load($this
->getWorkspaceId());
\Drupal::service('multiversion.entity_index.factory')
->get('multiversion.entity_index.rev.tree', $workspace)
->updateTree($entity, $branch);
}
protected function buildRevisionBranch(EntityInterface $entity) {
$branch = [];
$rev = $entity->_rev->value;
$revisions = $entity->_rev->revisions;
list($i) = explode('-', $rev);
$count_revisions = count($revisions);
if ($count_revisions > $i && $entity
->isNew()) {
$i = $count_revisions + 1;
}
if ($entity->_rev->new_edit || $entity->_rev->is_stub) {
$parent_rev = $i == 0 ? 0 : $rev;
if (!$entity->_rev->is_stub) {
$rev = \Drupal::service('multiversion.manager')
->newRevisionId($entity, $i);
}
list(, $hash) = explode('-', $rev);
$entity->_rev->value = $rev;
$entity->_rev->revisions = [
$hash,
];
$branch[$rev] = [
$parent_rev,
];
if ($parent_rev != 0) {
list(, $parent_hash) = explode('-', $parent_rev);
$entity->_rev->revisions = [
$hash,
$parent_hash,
];
}
}
else {
for ($c = 0; $c < count($revisions); ++$c) {
$p = $c + 1;
$rev = $i-- . '-' . $revisions[$c];
$parent_rev = isset($revisions[$p]) ? $i . '-' . $revisions[$p] : 0;
$branch[$rev] = [
$parent_rev,
];
}
}
return $branch;
}
protected function doSave($id, EntityInterface $entity) {
if ($entity->_rev->is_stub || $this->entityType
->get('local') || !empty($entity->original) && $entity->original->_rev->is_stub) {
$entity
->isDefaultRevision(TRUE);
}
else {
$entity
->setNewRevision();
if (!$entity
->isNew()) {
$workspace = Workspace::load($this
->getWorkspaceId());
$index_factory = \Drupal::service('multiversion.entity_index.factory');
$tree = $index_factory
->get('multiversion.entity_index.rev.tree', $workspace);
$default_rev = $tree
->getDefaultRevision($entity
->uuid());
if (empty($default_rev) || $entity->_rev->value == $default_rev) {
$entity
->isDefaultRevision(TRUE);
}
else {
$entity
->isDefaultRevision(FALSE);
}
}
else {
$entity
->isDefaultRevision(TRUE);
}
}
return parent::doSave($id, $entity);
}
public function delete(array $entities) {
$ids = [];
foreach ($entities as $entity) {
$ids[] = $entity
->id();
$entity->_deleted->value = TRUE;
$this
->save($entity);
}
$this
->resetCache($ids);
}
public function deleteRevision($revision_id) {
}
public function purge(array $entities) {
parent::delete($entities);
}
protected function trackConflicts(EntityInterface $entity) {
$workspace = Workspace::load($this
->getWorkspaceId());
$conflictTracker = \Drupal::service('multiversion.conflict_tracker')
->useWorkspace($workspace);
$index_factory = \Drupal::service('multiversion.entity_index.factory');
$tree = $index_factory
->get('multiversion.entity_index.rev.tree', $workspace);
$conflicts = $tree
->getConflicts($entity
->uuid());
if ($conflicts) {
$conflictTracker
->add($entity
->uuid(), $conflicts, TRUE);
}
else {
$conflictTracker
->resolveAll($entity
->uuid());
}
}
}