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@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@0: $result = $storage->getQuery() Chris@0: ->latestRevision() Chris@0: ->condition($this->entityTypeManager->getDefinition($entity_type_id)->getKey('id'), $entity_id) Chris@0: // No access check is performed here since this is an API function and Chris@0: // should return the same ID regardless of the current user. Chris@0: ->accessCheck(FALSE) Chris@0: ->execute(); Chris@0: if ($result) { Chris@0: 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@0: $result = $storage->getQuery() Chris@0: ->currentRevision() Chris@0: ->condition($this->entityTypeManager->getDefinition($entity_type_id)->getKey('id'), $entity_id) Chris@0: // No access check is performed here since this is an API function and Chris@0: // should return the same ID regardless of the current user. Chris@0: ->accessCheck(FALSE) Chris@0: ->execute(); Chris@0: if ($result) { Chris@0: 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@0: $result = FALSE; Chris@0: if ($this->isModeratedEntity($entity)) { Chris@0: /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */ Chris@0: $storage = $this->entityTypeManager->getStorage($entity->getEntityTypeId()); Chris@0: $latest_revision_id = $storage->getLatestTranslationAffectedRevisionId($entity->id(), $entity->language()->getId()); Chris@0: $default_revision_id = $entity->isDefaultRevision() && !$entity->isNewRevision() && ($revision_id = $entity->getRevisionId()) ? Chris@0: $revision_id : $this->getDefaultRevisionId($entity->getEntityTypeId(), $entity->id()); Chris@0: if ($latest_revision_id != $default_revision_id) { Chris@0: /** @var \Drupal\Core\Entity\ContentEntityInterface $latest_revision */ Chris@0: $latest_revision = $storage->loadRevision($latest_revision_id); Chris@0: $result = !$latest_revision->wasDefaultRevision(); Chris@0: } Chris@0: } Chris@0: 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@4: // If no default revision could be loaded, the entity has not yet been Chris@4: // saved. In this case the moderation_state of the unsaved entity can be Chris@4: // used, since once saved it will become the default. Chris@4: $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@0: $translation = $default_revision->getTranslation($language->getId()); Chris@0: // If the moderation state is empty, it was not stored yet so no point Chris@0: // in doing further work. Chris@0: $moderation_state = $translation->moderation_state->value; Chris@0: if (!$moderation_state) { Chris@0: continue; Chris@0: } Chris@0: // Return TRUE if a translation with a published state is found. Chris@0: 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@0: $bundles = $this->bundleInfo->getBundleInfo($entity->getEntityTypeId()); Chris@0: if (isset($bundles[$entity->bundle()]['workflow'])) { Chris@0: return $this->entityTypeManager->getStorage('workflow')->load($bundles[$entity->bundle()]['workflow']); Chris@0: }; Chris@0: return NULL; Chris@0: } Chris@0: Chris@4: /** Chris@4: * {@inheritdoc} Chris@4: */ Chris@4: public function getUnsupportedFeatures(EntityTypeInterface $entity_type) { Chris@4: $features = []; Chris@4: // Test if entity is publishable. Chris@4: if (!$entity_type->entityClassImplements(EntityPublishedInterface::class)) { Chris@4: $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@4: } Chris@4: return $features; Chris@4: } Chris@4: Chris@0: }