Loading core/modules/comment/src/Plugin/EntityReferenceSelection/CommentSelection.php +30 −2 Original line number Diff line number Diff line Loading @@ -63,6 +63,27 @@ public function validateReferenceableNewEntities(array $entities) { return $entities; } /** * {@inheritdoc} */ public function validateReferenceableEntities(array $ids) { $result = []; if ($ids) { $target_type = $this->configuration['target_type']; $entity_type = $this->entityTypeManager->getDefinition($target_type); $query = $this->buildEntityQuery(); // Mirror the conditions checked in buildEntityQuery(). if (!$this->currentUser->hasPermission('administer comments')) { $query->condition('status', 1); } $result = $query ->condition($entity_type->getKey('id'), $ids, 'IN') ->execute(); } return $result; } /** * {@inheritdoc} */ Loading @@ -77,9 +98,16 @@ public function entityQueryAlter(SelectInterface $query) { $query->innerJoin($data_table, NULL, "[base_table].[cid] = [$data_table].[cid] AND [$data_table].[default_langcode] = 1"); } // Find the host entity type the comment field is on. // Historically, comments were always linked to 'node' entities, but that is // no longer the case, as the 'node' module might not even be enabled. // Comments can now be linked to any entity and they can also be referenced // by other entities, so we won't have a single table to join to. That // actually means that we can no longer optimize the query on those cases. // However, the most common case remains to be comment replies, and in this // case, we can get the host entity type if the 'entity' value is present // and perform the extra joins and alterations needed. $comment = $this->getConfiguration()['entity']; if ($comment) { if ($comment instanceof CommentInterface) { $host_entity_type_id = $comment->getCommentedEntityTypeId(); /** @var \Drupal\Core\Entity\EntityTypeInterface $host_entity_type */ Loading core/modules/comment/tests/src/Functional/CommentEntityReferenceTest.php 0 → 100644 +124 −0 Original line number Diff line number Diff line <?php namespace Drupal\Tests\comment\Functional; use Drupal\comment\Entity\Comment; use Drupal\Tests\field\Traits\EntityReferenceTestTrait; /** * Tests that comments behave correctly when added as entity references. * * @group comment */ class CommentEntityReferenceTest extends CommentTestBase { use EntityReferenceTestTrait; /** * {@inheritdoc} */ protected $defaultTheme = 'stark'; /** * A second test node containing references to comments. * * @var \Drupal\node\NodeInterface */ protected $node2; /** * A comment linked to a node. * * @var \Drupal\comment\CommentInterface */ protected $comment; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); $this->createEntityReferenceField( 'node', 'article', 'entity_reference_comment', 'Entity Reference Comment', 'comment', 'default', ['target_bundles' => ['comment']] ); \Drupal::service('entity_display.repository') ->getFormDisplay('node', 'article') ->setComponent('entity_reference_comment', ['type' => 'options_select']) ->save(); \Drupal::service('entity_display.repository') ->getViewDisplay('node', 'article') ->setComponent('entity_reference_comment', ['type' => 'entity_reference_label']) ->save(); $administratorUser = $this->drupalCreateUser([ 'skip comment approval', 'post comments', 'access comments', 'access content', 'administer nodes', 'administer comments', 'bypass node access', ]); $this->drupalLogin($administratorUser); $this->node = $this->drupalCreateNode(['type' => 'article', 'promote' => 1, 'uid' => $this->webUser->id()]); $this->comment = $this->postComment($this->node, $this->randomMachineName(), $this->randomMachineName()); $this->assertInstanceOf(Comment::class, $this->comment); $this->node2 = $this->drupalCreateNode([ 'title' => $this->randomMachineName(), 'type' => 'article', ]); } /** * Tests that comments are correctly saved as entity references. */ public function testCommentAsEntityReference() { // Load the node and save it. $edit = [ 'entity_reference_comment' => $this->comment->id(), ]; $this->drupalGet('node/' . $this->node2->id() . '/edit'); $this->submitForm($edit, 'Save'); $this->assertSession()->statusCodeEquals(200); $this->assertSession()->pageTextContains('has been updated'); // Make sure the comment is linked. $this->assertSession()->pageTextContains($this->comment->label()); } /** * Tests that comments of unpublished are not shown. */ public function testCommentOfUnpublishedNodeBypassAccess() { // Unpublish the node that has the comment. $this->node->setUnpublished()->save(); // When the user has 'bypass node access' permission, they can still set it. $edit = [ 'entity_reference_comment' => $this->comment->id(), ]; $this->drupalGet('node/' . $this->node2->id() . '/edit'); $this->submitForm($edit, 'Save'); $this->assertSession()->statusCodeEquals(200); $this->assertSession()->pageTextContains('has been updated'); // Comment is seen as administrator user. $this->assertSession()->pageTextContains($this->comment->label()); // But not as anonymous. $this->drupalLogout(); $this->drupalGet('node/' . $this->node2->id()); $this->assertSession()->pageTextContains($this->node2->label()); $this->assertSession()->pageTextNotContains($this->comment->label()); } } core/modules/comment/tests/src/Kernel/CommentValidationTest.php +103 −0 Original line number Diff line number Diff line Loading @@ -3,8 +3,12 @@ namespace Drupal\Tests\comment\Kernel; use Drupal\comment\CommentInterface; use Drupal\comment\Entity\Comment; use Drupal\comment\Entity\CommentType; use Drupal\comment\Tests\CommentTestTrait; use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; use Drupal\node\Entity\Node; use Drupal\Tests\field\Traits\EntityReferenceTestTrait; use Drupal\user\Entity\User; /** Loading @@ -13,6 +17,8 @@ * @group comment */ class CommentValidationTest extends EntityKernelTestBase { use CommentTestTrait; use EntityReferenceTestTrait; /** * Modules to install. Loading @@ -27,6 +33,7 @@ class CommentValidationTest extends EntityKernelTestBase { protected function setUp(): void { parent::setUp(); $this->installSchema('comment', ['comment_entity_statistics']); $this->installConfig(['comment']); } /** Loading Loading @@ -180,6 +187,102 @@ public function testValidation() { $this->assertEquals('The specified author name does not match the comment author.', $violations[0]->getMessage()); } /** * Tests that comments of unpublished nodes are not valid. */ public function testValidationOfCommentOfUnpublishedNode() { // Create a page node type. $this->entityTypeManager->getStorage('node_type')->create([ 'type' => 'page', 'name' => 'page', ])->save(); // Create a comment type. CommentType::create([ 'id' => 'comment', 'label' => 'Default comments', 'description' => 'Default comment field', 'target_entity_type_id' => 'node', ])->save(); // Add comment and entity reference comment fields. $this->addDefaultCommentField('node', 'page', 'comment'); $this->createEntityReferenceField( 'node', 'page', 'entity_reference_comment', 'Entity Reference Comment', 'comment', 'default', ['target_bundles' => ['comment']] ); $comment_admin_user = $this->drupalCreateUser([ 'skip comment approval', 'post comments', 'access comments', 'access content', 'administer nodes', 'administer comments', 'bypass node access', ]); $comment_non_admin_user = $this->drupalCreateUser([ 'access comments', 'post comments', 'create page content', 'edit own comments', 'skip comment approval', 'access content', ]); // Create a node with a comment and make it unpublished. $node1 = $this->entityTypeManager->getStorage('node')->create([ 'type' => 'page', 'title' => 'test 1', 'promote' => 1, 'status' => 0, 'uid' => $comment_non_admin_user->id(), ]); $node1->save(); $comment1 = $this->entityTypeManager->getStorage('comment')->create([ 'entity_id' => $node1->id(), 'entity_type' => 'node', 'field_name' => 'comment', 'comment_body' => $this->randomMachineName(), ]); $comment1->save(); $this->assertInstanceOf(Comment::class, $comment1); // Create a second published node. /** @var \Drupal\node\Entity\Node $node2 */ $node2 = $this->entityTypeManager->getStorage('node')->create([ 'type' => 'page', 'title' => 'test 2', 'promote' => 1, 'status' => 1, 'uid' => $comment_non_admin_user->id(), ]); $node2->save(); // Test the validation API directly. $this->drupalSetCurrentUser($comment_non_admin_user); $this->assertEquals(\Drupal::currentUser()->id(), $comment_non_admin_user->id()); $node2->set('entity_reference_comment', $comment1->id()); $violations = $node2->validate(); $this->assertCount(1, $violations); $this->assertEquals('entity_reference_comment.0.target_id', $violations[0]->getPropertyPath()); $this->assertEquals(t('This entity (%type: %name) cannot be referenced.', [ '%type' => $comment1->getEntityTypeId(), '%name' => $comment1->id(), ]), $violations[0]->getMessage()); $this->drupalSetCurrentUser($comment_admin_user); $this->assertEquals(\Drupal::currentUser()->id(), $comment_admin_user->id()); $node2->set('entity_reference_comment', $comment1->id()); $violations = $node2->validate(); $this->assertCount(0, $violations); } /** * Verifies that a length violation exists for the given field. * Loading Loading
core/modules/comment/src/Plugin/EntityReferenceSelection/CommentSelection.php +30 −2 Original line number Diff line number Diff line Loading @@ -63,6 +63,27 @@ public function validateReferenceableNewEntities(array $entities) { return $entities; } /** * {@inheritdoc} */ public function validateReferenceableEntities(array $ids) { $result = []; if ($ids) { $target_type = $this->configuration['target_type']; $entity_type = $this->entityTypeManager->getDefinition($target_type); $query = $this->buildEntityQuery(); // Mirror the conditions checked in buildEntityQuery(). if (!$this->currentUser->hasPermission('administer comments')) { $query->condition('status', 1); } $result = $query ->condition($entity_type->getKey('id'), $ids, 'IN') ->execute(); } return $result; } /** * {@inheritdoc} */ Loading @@ -77,9 +98,16 @@ public function entityQueryAlter(SelectInterface $query) { $query->innerJoin($data_table, NULL, "[base_table].[cid] = [$data_table].[cid] AND [$data_table].[default_langcode] = 1"); } // Find the host entity type the comment field is on. // Historically, comments were always linked to 'node' entities, but that is // no longer the case, as the 'node' module might not even be enabled. // Comments can now be linked to any entity and they can also be referenced // by other entities, so we won't have a single table to join to. That // actually means that we can no longer optimize the query on those cases. // However, the most common case remains to be comment replies, and in this // case, we can get the host entity type if the 'entity' value is present // and perform the extra joins and alterations needed. $comment = $this->getConfiguration()['entity']; if ($comment) { if ($comment instanceof CommentInterface) { $host_entity_type_id = $comment->getCommentedEntityTypeId(); /** @var \Drupal\Core\Entity\EntityTypeInterface $host_entity_type */ Loading
core/modules/comment/tests/src/Functional/CommentEntityReferenceTest.php 0 → 100644 +124 −0 Original line number Diff line number Diff line <?php namespace Drupal\Tests\comment\Functional; use Drupal\comment\Entity\Comment; use Drupal\Tests\field\Traits\EntityReferenceTestTrait; /** * Tests that comments behave correctly when added as entity references. * * @group comment */ class CommentEntityReferenceTest extends CommentTestBase { use EntityReferenceTestTrait; /** * {@inheritdoc} */ protected $defaultTheme = 'stark'; /** * A second test node containing references to comments. * * @var \Drupal\node\NodeInterface */ protected $node2; /** * A comment linked to a node. * * @var \Drupal\comment\CommentInterface */ protected $comment; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); $this->createEntityReferenceField( 'node', 'article', 'entity_reference_comment', 'Entity Reference Comment', 'comment', 'default', ['target_bundles' => ['comment']] ); \Drupal::service('entity_display.repository') ->getFormDisplay('node', 'article') ->setComponent('entity_reference_comment', ['type' => 'options_select']) ->save(); \Drupal::service('entity_display.repository') ->getViewDisplay('node', 'article') ->setComponent('entity_reference_comment', ['type' => 'entity_reference_label']) ->save(); $administratorUser = $this->drupalCreateUser([ 'skip comment approval', 'post comments', 'access comments', 'access content', 'administer nodes', 'administer comments', 'bypass node access', ]); $this->drupalLogin($administratorUser); $this->node = $this->drupalCreateNode(['type' => 'article', 'promote' => 1, 'uid' => $this->webUser->id()]); $this->comment = $this->postComment($this->node, $this->randomMachineName(), $this->randomMachineName()); $this->assertInstanceOf(Comment::class, $this->comment); $this->node2 = $this->drupalCreateNode([ 'title' => $this->randomMachineName(), 'type' => 'article', ]); } /** * Tests that comments are correctly saved as entity references. */ public function testCommentAsEntityReference() { // Load the node and save it. $edit = [ 'entity_reference_comment' => $this->comment->id(), ]; $this->drupalGet('node/' . $this->node2->id() . '/edit'); $this->submitForm($edit, 'Save'); $this->assertSession()->statusCodeEquals(200); $this->assertSession()->pageTextContains('has been updated'); // Make sure the comment is linked. $this->assertSession()->pageTextContains($this->comment->label()); } /** * Tests that comments of unpublished are not shown. */ public function testCommentOfUnpublishedNodeBypassAccess() { // Unpublish the node that has the comment. $this->node->setUnpublished()->save(); // When the user has 'bypass node access' permission, they can still set it. $edit = [ 'entity_reference_comment' => $this->comment->id(), ]; $this->drupalGet('node/' . $this->node2->id() . '/edit'); $this->submitForm($edit, 'Save'); $this->assertSession()->statusCodeEquals(200); $this->assertSession()->pageTextContains('has been updated'); // Comment is seen as administrator user. $this->assertSession()->pageTextContains($this->comment->label()); // But not as anonymous. $this->drupalLogout(); $this->drupalGet('node/' . $this->node2->id()); $this->assertSession()->pageTextContains($this->node2->label()); $this->assertSession()->pageTextNotContains($this->comment->label()); } }
core/modules/comment/tests/src/Kernel/CommentValidationTest.php +103 −0 Original line number Diff line number Diff line Loading @@ -3,8 +3,12 @@ namespace Drupal\Tests\comment\Kernel; use Drupal\comment\CommentInterface; use Drupal\comment\Entity\Comment; use Drupal\comment\Entity\CommentType; use Drupal\comment\Tests\CommentTestTrait; use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; use Drupal\node\Entity\Node; use Drupal\Tests\field\Traits\EntityReferenceTestTrait; use Drupal\user\Entity\User; /** Loading @@ -13,6 +17,8 @@ * @group comment */ class CommentValidationTest extends EntityKernelTestBase { use CommentTestTrait; use EntityReferenceTestTrait; /** * Modules to install. Loading @@ -27,6 +33,7 @@ class CommentValidationTest extends EntityKernelTestBase { protected function setUp(): void { parent::setUp(); $this->installSchema('comment', ['comment_entity_statistics']); $this->installConfig(['comment']); } /** Loading Loading @@ -180,6 +187,102 @@ public function testValidation() { $this->assertEquals('The specified author name does not match the comment author.', $violations[0]->getMessage()); } /** * Tests that comments of unpublished nodes are not valid. */ public function testValidationOfCommentOfUnpublishedNode() { // Create a page node type. $this->entityTypeManager->getStorage('node_type')->create([ 'type' => 'page', 'name' => 'page', ])->save(); // Create a comment type. CommentType::create([ 'id' => 'comment', 'label' => 'Default comments', 'description' => 'Default comment field', 'target_entity_type_id' => 'node', ])->save(); // Add comment and entity reference comment fields. $this->addDefaultCommentField('node', 'page', 'comment'); $this->createEntityReferenceField( 'node', 'page', 'entity_reference_comment', 'Entity Reference Comment', 'comment', 'default', ['target_bundles' => ['comment']] ); $comment_admin_user = $this->drupalCreateUser([ 'skip comment approval', 'post comments', 'access comments', 'access content', 'administer nodes', 'administer comments', 'bypass node access', ]); $comment_non_admin_user = $this->drupalCreateUser([ 'access comments', 'post comments', 'create page content', 'edit own comments', 'skip comment approval', 'access content', ]); // Create a node with a comment and make it unpublished. $node1 = $this->entityTypeManager->getStorage('node')->create([ 'type' => 'page', 'title' => 'test 1', 'promote' => 1, 'status' => 0, 'uid' => $comment_non_admin_user->id(), ]); $node1->save(); $comment1 = $this->entityTypeManager->getStorage('comment')->create([ 'entity_id' => $node1->id(), 'entity_type' => 'node', 'field_name' => 'comment', 'comment_body' => $this->randomMachineName(), ]); $comment1->save(); $this->assertInstanceOf(Comment::class, $comment1); // Create a second published node. /** @var \Drupal\node\Entity\Node $node2 */ $node2 = $this->entityTypeManager->getStorage('node')->create([ 'type' => 'page', 'title' => 'test 2', 'promote' => 1, 'status' => 1, 'uid' => $comment_non_admin_user->id(), ]); $node2->save(); // Test the validation API directly. $this->drupalSetCurrentUser($comment_non_admin_user); $this->assertEquals(\Drupal::currentUser()->id(), $comment_non_admin_user->id()); $node2->set('entity_reference_comment', $comment1->id()); $violations = $node2->validate(); $this->assertCount(1, $violations); $this->assertEquals('entity_reference_comment.0.target_id', $violations[0]->getPropertyPath()); $this->assertEquals(t('This entity (%type: %name) cannot be referenced.', [ '%type' => $comment1->getEntityTypeId(), '%name' => $comment1->id(), ]), $violations[0]->getMessage()); $this->drupalSetCurrentUser($comment_admin_user); $this->assertEquals(\Drupal::currentUser()->id(), $comment_admin_user->id()); $node2->set('entity_reference_comment', $comment1->id()); $violations = $node2->validate(); $this->assertCount(0, $violations); } /** * Verifies that a length violation exists for the given field. * Loading