- πΊπΈUnited States bkosborne New Jersey, USA
- π¨π¦Canada dalin Guelph, π¨π¦, π
Another place this pops up:
1. Use
getParentEntity()
somewhere.
2. View a non-default revision of the node. `getParentEntity()` is always returning the default revision of the parent, so you see something broken.If the parent is a node there's awkward ways to work around this by getting the route object. But if the parent is another paragraph, you're screwed.
- πΈπͺSweden twod Sweden
Yeah, this really bites sometimes.
We've got a use case doing a lot of programmatic edits to individual paragraphs and had to come up with a helper like this instead of calling
getParentEntity()
directly:The extra logging is there because we've hit all those cases with existing content which previously just called
getParentEntity()
and assumed it "did the right thing".use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\RevisionableStorageInterface; use Drupal\node\NodeInterface; use Drupal\paragraphs\ParagraphInterface; trait ParagraphHelpers { protected EntityTypeManagerInterface $entityTypeManager; /** * Get parent revision which actually refrences a paragraph. * * Paragraph parent references do not include the parent revision, so we may * need to check multiple parent revisions to find the one which actually * references the specific revision of the passed in paragraph. * * @param \Drupal\node\NodeInterface $node * The top node. * @param \Drupal\paragraphs\ParagraphInterface $paragraph * A paragraph. * @param string|null $langcode * The language to load, default to the same as the paragraph. * * @return \Drupal\Core\Entity\ContentEntityInterface|null * The parent entity revision referencing $paragraph, or NULL if not found. */ protected function getParagraphParentRevision(NodeInterface $node, ParagraphInterface $paragraph, ?string $langcode = NULL): ?ContentEntityInterface { // Try the latest parent revision. /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $parent_storage */ $parent_storage = $this->entityTypeManager->getStorage($paragraph->get('parent_type')->value); assert($parent_storage instanceof RevisionableStorageInterface, 'Can only handle revisionable entities.'); $latest_parent_revision = $parent_storage->getLatestRevisionId($paragraph->get('parent_id')->value); $parent = $parent_storage->loadRevision($latest_parent_revision); /** @var \Drupal\Core\Entity\ContentEntityInterface $parent */ $current_paragraph_delta = $this->getParagraphDelta($paragraph, $parent); // Try the default parent revision. if ($current_paragraph_delta === FALSE) { $parent = $paragraph->getParentEntity(); $current_paragraph_delta = $this->getParagraphDelta($paragraph, $parent); } // Brute force fallback. if ($current_paragraph_delta === FALSE) { // Sanity checks. while ($parent instanceof ParagraphInterface) { $parent = $parent->getParentEntity(); } if (!$parent instanceof NodeInterface || $parent->id() !== $node->id()) { $this->logger->error('Something is very wrong with paragraph @id (@rid) in node @nid (@vid)!', [ '@id' => $paragraph->id(), '@rid' => $paragraph->getRevisionId(), '@nid' => $parent->id(), '@vid' => $parent->getRevisionId(), ]); throw new \LogicException('The passed in node is not the parent of the paragraph.'); } // We may have a broken node structure if it comes to this, but at // least we'll be able to edit it and preserve the structure. $tree = $this->getFlatParagraphTree($node); $paragraph_data = $tree[$paragraph->id()] ?? NULL; if ($paragraph_data && $paragraph_data['revision'] === $paragraph->getRevisionId() && $paragraph_data['parentType'] === $paragraph->get('parent_type')->value && $paragraph_data['parentId'] === $paragraph->get('parent_id')->value ) { if ($node->isLatestRevision() || $node->isDefaultRevision()) { $this->logger->notice('Paragraph @id (@rid) in node @nid (@vid) was not referenced from the latest or default', [ '@id' => $paragraph->id(), '@rid' => $paragraph->getRevisionId(), '@nid' => $parent->id(), '@vid' => $parent->getRevisionId(), ]); } /** @var \Drupal\Core\Entity\ContentEntityInterface|null $parent */ $parent = $parent_storage->loadRevision($paragraph_data['parentRevision']); $current_paragraph_delta = $parent instanceof ContentEntityInterface ? $this->getParagraphDelta($paragraph, $parent) : FALSE; } } if ($current_paragraph_delta === FALSE) { $this->logger->error('Paragraph @id (@rid) in node @nid (@vid) was not referenced from any parent.', [ '@id' => $paragraph->id(), '@rid' => $paragraph->getRevisionId(), '@nid' => $parent->id(), '@vid' => $parent->getRevisionId(), ]); } return $current_paragraph_delta !== FALSE ? $parent : NULL; } /** * Get at which delta in the parent field a paragraph is referenced. * * @param \Drupal\paragraphs\ParagraphInterface $paragraph * A paragraph. * @param \Drupal\Core\Entity\ContentEntityInterface $parent * The parent element. * * @return false|int|string * The delta as an int/string or FALSE if not found. */ protected function getParagraphDelta(ParagraphInterface $paragraph, ContentEntityInterface $parent) { $field_items = $parent->get($paragraph->parent_field_name->value); foreach ($field_items as $delta => $item) { // Explicitly compare ids first to avoid loading a new instance of the // referenced revision, which gives a clone since they are not cached in // storage, but may be cached on the parent's reference field item. if ( ( !$paragraph->isNew() && ( $item->target_revision_id === $paragraph->getRevisionId() && $item->target_id = $paragraph->id() ) ) || ( $paragraph->isNew() && !isset($item->target_revision_id) && $item->entity && $item->entity === $paragraph ) ) { return $delta; } } return FALSE; } }
- π·π΄Romania amateescu
Just closed π Nested paragraphs automatically publish, even if the parent is a draft Closed: duplicate as a duplicate of this issue, updating the parent of this one.
- πΊπ¦Ukraine abyss
Hi @amateescu, this is a bit strange, if you think that there is a duplicate problem here, then shouldn't you close this issue (child) instead of the parent issue which is described in #2807371: META Support Content Moderation module β ?