Problem/Motivation

Quoting myself from #2950869: Entity queries querying the latest revision very slow with lots of revisions:

And in \Drupal\content_moderation\aEntityOperations::entityView(), we are *first* checking if it's the latest revision and only after that check if it's the default revision. I think we can also optimize that a lot and if the entity is the published default revision, then return early and save lots of queries and moderation entity loading.

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Comments

Berdir created an issue. See original summary.

berdir’s picture

Status: Active » Needs review
StatusFileSize
new2.13 KB

Something like this.

timmillwood’s picture

Status: Needs review » Reviewed & tested by the community

Makes sense, LGTM!

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/modules/content_moderation/src/EntityOperations.php
    @@ -278,15 +279,24 @@ public function entityView(array &$build, EntityInterface $entity, EntityViewDis
    +    if (($entity->isDefaultRevision() || $entity->wasDefaultRevision())) {
    

    Unnecessary () - however I suggest a re-implementation below that makes them necessary again.

  2. +++ b/core/modules/content_moderation/src/EntityOperations.php
    @@ -278,15 +279,24 @@ public function entityView(array &$build, EntityInterface $entity, EntityViewDis
    +      // If the entity implements EntityPublishedInterface directly, check that
    +      // first, otherwise fall back to check through the workflow state.
    +      if ($entity instanceof EntityPublishedInterface) {
    +        if ($entity->isPublished()) {
    +          return;
    +        }
    +      }
    +      elseif ($moderation_state = $entity->get('moderation_state')->value) {
    +        $workflow = $this->moderationInfo->getWorkflowForEntity($entity);
    +        if ($workflow->getTypePlugin()->getState($moderation_state)->isPublishedState()) {
    +          return;
    +        }
    +      }
    

    I think this might be simpler if moved to a helper method. For example:

     /**
       * Act on entities being assembled before rendering.
       *
       * @see hook_entity_view()
       * @see EntityFieldManagerInterface::getExtraFields()
       */
      public function entityView(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
        /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
        if (!$this->moderationInfo->isModeratedEntity($entity)) {
          return;
        }
        if (isset($entity->in_preview) && $entity->in_preview) {
          return;
        }
        // If the component is not defined for this display, we have nothing to do.
        if (!$display->getComponent('content_moderation_control')) {
          return;
        }
        // The moderation form should be displayed only when viewing the latest
        // (translation-affecting) revision, unless it was created as published
        // default revision.
        if (($entity->isDefaultRevision() || $entity->wasDefaultRevision()) && $this->isPublished($entity)) {
          return;
        }
        if (!$entity->isLatestRevision() && !$entity->isLatestTranslationAffectedRevision()) {
          return;
        }
    
        $build['content_moderation_control'] = $this->formBuilder->getForm(EntityModerationForm::class, $entity);
      }
    
      /**
       * Checks if the entity is published.
       * 
       * This method is optimised to not have to unnecessarily load the moderation
       * state and workflow if it is not required.
       *
       * @param $entity
       *
       * @return bool
       */
      protected function isPublished($entity) {
        // If the entity implements EntityPublishedInterface directly, check that
        // first, otherwise fall back to check through the workflow state.
        if ($entity instanceof EntityPublishedInterface) {
          return $entity->isPublished();
        }
        if ($moderation_state = $entity->get('moderation_state')->value) {
          $workflow = $this->moderationInfo->getWorkflowForEntity($entity);
          return $workflow->getTypePlugin()->getState($moderation_state)->isPublishedState();
        }
        return FALSE;
      }
    
berdir’s picture

Status: Needs work » Needs review
StatusFileSize
new2.77 KB

Works for me, all that logic distracts from what we are actually doing there.

No interdiff, that's bigger than the patch.

amateescu’s picture

Status: Needs review » Reviewed & tested by the community

Looks great to me! If someone could fix this at some point, it would be even better:

+++ b/core/modules/content_moderation/src/EntityOperations.php
@@ -278,17 +280,39 @@ public function entityView(array &$build, EntityInterface $entity, EntityViewDis
+   * This method is optimised to not have to unnecessarily load the moderation

"optimised" -> "optimized" :)

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Fixed #6 on commit. Committed e9dd745 and pushed to 8.6.x. Thanks!

  • alexpott committed e9dd745 on 8.6.x
    Issue #2983837 by Berdir, alexpott, amateescu: Optimize EntityOperations...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.