Issue #2614720 by quietone, roderik, ofry, Dylan Donkersgoed, Deepak Goyal, samiullah, jonathanshaw, benjifisher, larowlan, Rewted, Ruedische, KlemenDEV, ao2, abramm, vadim.hirbu, HiMyNameIsSeb, dionsj, mgp_novicell, scalas89, rollins, dmytro-aragorn, hchonov, mayurjadhav, paranojik, nplowman: Fatal errors while loading/building orphaned comments

merge-requests/7/head
catch 2020-08-27 10:25:44 +01:00
parent 9e546b3678
commit 9beb71e610
5 changed files with 150 additions and 12 deletions

View File

@ -607,9 +607,8 @@ function template_preprocess_comment(&$variables) {
$variables['submitted'] = t('Submitted by @username on @datetime', ['@username' => $variables['author'], '@datetime' => $variables['created']]);
if ($comment->hasParentComment()) {
if ($comment_parent = $comment->getParentComment()) {
// Fetch and store the parent comment information for use in templates.
$comment_parent = $comment->getParentComment();
$account_parent = $comment_parent->getOwner();
$variables['parent_comment'] = $comment_parent;
$username = [

View File

@ -137,9 +137,9 @@ class CommentLazyBuilders implements TrustedCallbackInterface {
if (!$is_in_preview) {
/** @var \Drupal\comment\CommentInterface $entity */
$entity = $this->entityTypeManager->getStorage('comment')->load($comment_entity_id);
$commented_entity = $entity->getCommentedEntity();
$links['comment'] = $this->buildLinks($entity, $commented_entity);
if ($commented_entity = $entity->getCommentedEntity()) {
$links['comment'] = $this->buildLinks($entity, $commented_entity);
}
// Allow other modules to alter the comment links.
$hook_context = [

View File

@ -80,9 +80,11 @@ class CommentViewBuilder extends EntityViewBuilder {
/** @var \Drupal\comment\CommentInterface $entity */
// Store a threading field setting to use later in self::buildComponents().
$build['#comment_threaded'] = $entity->getCommentedEntity()
->getFieldDefinition($entity->getFieldName())
->getSetting('default_mode') === CommentManagerInterface::COMMENT_MODE_THREADED;
$commented_entity = $entity->getCommentedEntity();
$build['#comment_threaded'] =
is_null($commented_entity)
|| $commented_entity->getFieldDefinition($entity->getFieldName())
->getSetting('default_mode') === CommentManagerInterface::COMMENT_MODE_THREADED;
// If threading is enabled, don't render cache individual comments, but do
// keep the cacheability metadata, so it can bubble up.
if ($build['#comment_threaded']) {
@ -140,10 +142,12 @@ class CommentViewBuilder extends EntityViewBuilder {
// Commented entities already loaded after self::getBuildDefaults().
$commented_entity = $entity->getCommentedEntity();
// Set defaults if the commented_entity does not exist.
$bundle = $commented_entity ? $commented_entity->bundle() : '';
$is_node = $commented_entity ? $commented_entity->getEntityTypeId() === 'node' : NULL;
$build[$id]['#entity'] = $entity;
$build[$id]['#theme'] = 'comment__' . $entity->getFieldName() . '__' . $commented_entity->bundle();
$build[$id]['#theme'] = 'comment__' . $entity->getFieldName() . '__' . $bundle;
$display = $displays[$entity->bundle()];
if ($display->getComponent('links')) {
$build[$id]['links'] = [
@ -164,7 +168,7 @@ class CommentViewBuilder extends EntityViewBuilder {
$build[$id]['#attached'] = [];
}
$build[$id]['#attached']['library'][] = 'comment/drupal.comment-by-viewer';
if ($attach_history && $commented_entity->getEntityTypeId() === 'node') {
if ($attach_history && $is_node) {
$build[$id]['#attached']['library'][] = 'comment/drupal.comment-new-indicator';
// Embed the metadata for the comment "new" indicators on this node.

View File

@ -404,7 +404,8 @@ class Comment extends ContentEntityBase implements CommentInterface {
* {@inheritdoc}
*/
public function getAuthorName() {
if ($this->get('uid')->target_id) {
// If their is a valid user id and the user entity exists return the label.
if ($this->get('uid')->target_id && $this->get('uid')->entity) {
return $this->get('uid')->entity->label();
}
return $this->get('name')->value ?: \Drupal::config('user.settings')->get('anonymous');

View File

@ -0,0 +1,134 @@
<?php
namespace Drupal\Tests\comment\Kernel;
use Drupal\Core\Datetime\Entity\DateFormat;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\Tests\EntityViewTrait;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Tests loading and rendering orphan comments.
*
* @group comment
*/
class CommentOrphanTest extends EntityKernelTestBase {
use EntityViewTrait;
/**
* {@inheritdoc}
*/
protected static $modules = ['comment', 'node'];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('date_format');
$this->installEntitySchema('comment');
$this->installSchema('comment', ['comment_entity_statistics']);
}
/**
* Test loading/deleting/rendering orphaned comments.
*
* @dataProvider providerTestOrphan
*/
public function testOrphan($property) {
DateFormat::create([
'id' => 'fallback',
'label' => 'Fallback',
'pattern' => 'Y-m-d',
])->save();
$comment_storage = $this->entityTypeManager->getStorage('comment');
$node_storage = $this->entityTypeManager->getStorage('node');
// Create a page node type.
$this->entityTypeManager->getStorage('node_type')->create([
'type' => 'page',
'name' => 'page',
])->save();
$node = $node_storage->create([
'type' => 'page',
'title' => 'test',
]);
$node->save();
// Create comment field.
$this->entityTypeManager->getStorage('field_storage_config')->create([
'type' => 'text_long',
'entity_type' => 'node',
'field_name' => 'comment',
])->save();
// Add comment field to page content.
$this->entityTypeManager->getStorage('field_config')->create([
'field_storage' => FieldStorageConfig::loadByName('node', 'comment'),
'entity_type' => 'node',
'bundle' => 'page',
'label' => 'Comment',
])->save();
// Make two comments
$comment1 = $comment_storage->create([
'field_name' => 'comment',
'comment_body' => 'test',
'entity_id' => $node->id(),
'entity_type' => 'node',
'comment_type' => 'default',
])->save();
$comment_storage->create([
'field_name' => 'comment',
'comment_body' => 'test',
'entity_id' => $node->id(),
'entity_type' => 'node',
'comment_type' => 'default',
'pid' => $comment1,
])->save();
// Render the comments.
$renderer = \Drupal::service('renderer');
$comments = $comment_storage->loadMultiple();
foreach ($comments as $comment) {
$built = $this->buildEntityView($comment, 'full', NULL);
$renderer->renderPlain($built);
}
// Make comment 2 an orphan by setting the property to an invalid value.
\Drupal::database()->update('comment_field_data')
->fields([$property => 10])
->condition('cid', 2)
->execute();
$comment_storage->resetCache();
$node_storage->resetCache();
// Render the comments with an orphan comment.
$comments = $comment_storage->loadMultiple();
foreach ($comments as $comment) {
$built = $this->buildEntityView($comment, 'full', NULL);
$renderer->renderPlain($built);
}
$node = $node_storage->load($node->id());
$built = $this->buildEntityView($node, 'full', NULL);
$renderer->renderPlain($built);
}
/**
* Provides test data for testOrphan.
*/
public function providerTestOrphan() {
return [
['entity_id'],
['uid'],
['pid'],
];
}
}