Chris@0: entityTypeManager = $entity_type_manager; Chris@0: $this->bundleInfo = $bundle_info; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function isModeratedEntity(EntityInterface $entity) { Chris@0: if (!$entity instanceof ContentEntityInterface) { Chris@0: return FALSE; Chris@0: } Chris@0: Chris@0: return $this->shouldModerateEntitiesOfBundle($entity->getEntityType(), $entity->bundle()); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@18: public function isModeratedEntityType(EntityTypeInterface $entity_type) { Chris@18: $bundles = $this->bundleInfo->getBundleInfo($entity_type->id()); Chris@18: return !empty(array_column($bundles, 'workflow')); Chris@18: } Chris@18: Chris@18: /** Chris@18: * {@inheritdoc} Chris@18: */ Chris@0: public function canModerateEntitiesOfEntityType(EntityTypeInterface $entity_type) { Chris@0: return $entity_type->hasHandlerClass('moderation'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function shouldModerateEntitiesOfBundle(EntityTypeInterface $entity_type, $bundle) { Chris@0: if ($this->canModerateEntitiesOfEntityType($entity_type)) { Chris@0: $bundles = $this->bundleInfo->getBundleInfo($entity_type->id()); Chris@0: return isset($bundles[$bundle]['workflow']); Chris@0: } Chris@0: return FALSE; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getLatestRevision($entity_type_id, $entity_id) { Chris@0: if ($latest_revision_id = $this->getLatestRevisionId($entity_type_id, $entity_id)) { Chris@0: return $this->entityTypeManager->getStorage($entity_type_id)->loadRevision($latest_revision_id); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getLatestRevisionId($entity_type_id, $entity_id) { Chris@0: if ($storage = $this->entityTypeManager->getStorage($entity_type_id)) { Chris@12: $result = $storage->getQuery() Chris@12: ->latestRevision() Chris@0: ->condition($this->entityTypeManager->getDefinition($entity_type_id)->getKey('id'), $entity_id) Chris@12: // No access check is performed here since this is an API function and Chris@12: // should return the same ID regardless of the current user. Chris@12: ->accessCheck(FALSE) Chris@0: ->execute(); Chris@12: if ($result) { Chris@12: return key($result); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getDefaultRevisionId($entity_type_id, $entity_id) { Chris@0: if ($storage = $this->entityTypeManager->getStorage($entity_type_id)) { Chris@12: $result = $storage->getQuery() Chris@12: ->currentRevision() Chris@0: ->condition($this->entityTypeManager->getDefinition($entity_type_id)->getKey('id'), $entity_id) Chris@12: // No access check is performed here since this is an API function and Chris@12: // should return the same ID regardless of the current user. Chris@12: ->accessCheck(FALSE) Chris@0: ->execute(); Chris@12: if ($result) { Chris@12: return key($result); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getAffectedRevisionTranslation(ContentEntityInterface $entity) { Chris@0: foreach ($entity->getTranslationLanguages() as $language) { Chris@0: $translation = $entity->getTranslation($language->getId()); Chris@0: if (!$translation->isDefaultRevision() && $translation->isRevisionTranslationAffected()) { Chris@0: return $translation; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function isLatestRevision(ContentEntityInterface $entity) { Chris@0: return $entity->getRevisionId() == $this->getLatestRevisionId($entity->getEntityTypeId(), $entity->id()); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function hasPendingRevision(ContentEntityInterface $entity) { Chris@14: $result = FALSE; Chris@14: if ($this->isModeratedEntity($entity)) { Chris@14: /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */ Chris@14: $storage = $this->entityTypeManager->getStorage($entity->getEntityTypeId()); Chris@14: $latest_revision_id = $storage->getLatestTranslationAffectedRevisionId($entity->id(), $entity->language()->getId()); Chris@14: $default_revision_id = $entity->isDefaultRevision() && !$entity->isNewRevision() && ($revision_id = $entity->getRevisionId()) ? Chris@14: $revision_id : $this->getDefaultRevisionId($entity->getEntityTypeId(), $entity->id()); Chris@14: if ($latest_revision_id != $default_revision_id) { Chris@14: /** @var \Drupal\Core\Entity\ContentEntityInterface $latest_revision */ Chris@14: $latest_revision = $storage->loadRevision($latest_revision_id); Chris@14: $result = !$latest_revision->wasDefaultRevision(); Chris@14: } Chris@14: } Chris@14: return $result; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function isLiveRevision(ContentEntityInterface $entity) { Chris@0: $workflow = $this->getWorkflowForEntity($entity); Chris@0: return $this->isLatestRevision($entity) Chris@0: && $entity->isDefaultRevision() Chris@0: && $entity->moderation_state->value Chris@0: && $workflow->getTypePlugin()->getState($entity->moderation_state->value)->isPublishedState(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function isDefaultRevisionPublished(ContentEntityInterface $entity) { Chris@0: $workflow = $this->getWorkflowForEntity($entity); Chris@0: $default_revision = \Drupal::entityTypeManager()->getStorage($entity->getEntityTypeId())->load($entity->id()); Chris@17: // If no default revision could be loaded, the entity has not yet been Chris@17: // saved. In this case the moderation_state of the unsaved entity can be Chris@17: // used, since once saved it will become the default. Chris@17: $default_revision = $default_revision ?: $entity; Chris@0: Chris@0: // Ensure we are checking all translations of the default revision. Chris@0: if ($default_revision instanceof TranslatableInterface && $default_revision->isTranslatable()) { Chris@0: // Loop through each language that has a translation. Chris@0: foreach ($default_revision->getTranslationLanguages() as $language) { Chris@0: // Load the translated revision. Chris@14: $translation = $default_revision->getTranslation($language->getId()); Chris@14: // If the moderation state is empty, it was not stored yet so no point Chris@14: // in doing further work. Chris@14: $moderation_state = $translation->moderation_state->value; Chris@14: if (!$moderation_state) { Chris@14: continue; Chris@14: } Chris@0: // Return TRUE if a translation with a published state is found. Chris@14: if ($workflow->getTypePlugin()->getState($moderation_state)->isPublishedState()) { Chris@0: return TRUE; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: return $workflow->getTypePlugin()->getState($default_revision->moderation_state->value)->isPublishedState(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getWorkflowForEntity(ContentEntityInterface $entity) { Chris@18: return $this->getWorkflowForEntityTypeAndBundle($entity->getEntityTypeId(), $entity->bundle()); Chris@18: } Chris@18: Chris@18: /** Chris@18: * {@inheritdoc} Chris@18: */ Chris@18: public function getWorkflowForEntityTypeAndBundle($entity_type_id, $bundle_id) { Chris@18: $bundles = $this->bundleInfo->getBundleInfo($entity_type_id); Chris@18: if (isset($bundles[$bundle_id]['workflow'])) { Chris@18: return $this->entityTypeManager->getStorage('workflow')->load($bundles[$bundle_id]['workflow']); Chris@18: } Chris@0: return NULL; Chris@0: } Chris@0: Chris@17: /** Chris@17: * {@inheritdoc} Chris@17: */ Chris@17: public function getUnsupportedFeatures(EntityTypeInterface $entity_type) { Chris@17: $features = []; Chris@17: // Test if entity is publishable. Chris@17: if (!$entity_type->entityClassImplements(EntityPublishedInterface::class)) { Chris@17: $features['publishing'] = $this->t("@entity_type_plural_label do not support publishing statuses. For example, even after transitioning from a published workflow state to an unpublished workflow state they will still be visible to site visitors.", ['@entity_type_plural_label' => $entity_type->getCollectionLabel()]); Chris@17: } Chris@17: return $features; Chris@17: } Chris@17: Chris@0: }