diff --git a/core/modules/comment/tests/src/Kernel/CommentOrphanTest.php b/core/modules/comment/tests/src/Kernel/CommentOrphanTest.php new file mode 100644 index 0000000000..2adb118319 --- /dev/null +++ b/core/modules/comment/tests/src/Kernel/CommentOrphanTest.php @@ -0,0 +1,178 @@ +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. + $this->orphanComments([2], [$property]); + $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); + } + + /** + * Creates orphaned comments. + * + * Intentionally makes reference data (commented entity, parent comment, + * author) invalid, in the SQL storage backend. + * + * @param array $comment_ids + * IDs of comments to orphan. If empty, invalidate the most recent comment. + * @param array $fields + * Names of fields to change. Allowed values: 'pid', 'entity_id', 'uid'. If + * empty, all fields will be changed. + */ + public function orphanComments(array $comment_ids = [], array $fields = []) { + + $database = \Drupal::database(); + // Get the maximum parent/author and set it one higher; this emulates + // a parent/author which has been deleted after creating. + $query = $database->select('comment_field_data', 'c'); + $query->addExpression('MAX(cid)', 'cid_max'); + $query->addExpression('MAX(pid)', 'pid_max'); + $query->addExpression('MAX(uid)', 'uid_max'); + $query->addExpression('MAX(entity_id)', 'entity_id_max'); + $row = $query->execute()->fetchObject(); + if (!isset($row->pid_max) && isset($row->cid_max)) { + $row->pid_max = $row->cid_max; + } + + if (empty($comment_ids) && isset($row->cid_max)) { + $comment_ids = [$row->cid_max]; + } + + if (!empty($comment_ids)) { + $update_values = [ + 'entity_id' => $row->entity_id_max + 1, + 'pid' => $row->cid_max + 1, + 'uid' => $row->uid_max + 1, + ]; + if ($fields) { + $update_values = array_intersect_key($update_values, array_flip($fields)); + } + $database->update('comment_field_data') + ->fields($update_values) + ->condition('cid', $comment_ids) + ->execute(); + } + } + + /** + * Provides test data for testOrphan. + */ + public function providerTestOrphan() { + return [ + ['entity_id'], + ['uid'], + ['pid'], + ]; + } + +}