+++ b/core/modules/comment/comment.install
@@ -195,3 +196,29 @@ function comment_update_8400() {
+/**
+ * Set a value for thread_depth for all existing comments.
+ */
+function comment_update_8500() {
Since this adds an update hook, the upgrade path needs to be tested. Check out Drupal\Tests\comment\Functional\Update\CommentUpdateTest, as I think a new test method can just be added to that, and verify that the settings are indeed updated.
+++ b/core/modules/comment/comment.install
@@ -195,3 +196,29 @@ function comment_update_8400() {
+ $field->setSetting('thread_depth', 100);
+++ b/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php
@@ -112,6 +113,21 @@ public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
+ '#max' => 100,
The max thread depth should probably be a constant on the CommentInterface instead of hard-coding the number wherever it's used.
With the update hook, and the default value above, shouldn't this always be set now?
+++ b/core/modules/comment/tests/src/Functional/Update/CommentUpdateTest.php
@@ -71,4 +72,41 @@ public function testPublishedEntityKey() {
+ $results = $entity_query->execute();
+
+ // Check that none of the existing comment fields have the thread_depth setting.
+ /** @var \Drupal\field\FieldConfigStorage $field_config_storage */
+ $field_config_storage = \Drupal::entityTypeManager()->getStorage('field_config');
+ foreach ($results as $id) {
...
+ $results = $entity_query->execute();
I think an assert that these $results are non-empty would be valuable. Otherwise, here, and below, if for whatever reason it didn't load any comments, none of the assertions in the foreach loops would run.
Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.
Not a very big fan of settings a hard limit or suggesting a value. What if existing sites went beyond this value? I would rather allow a "not limited" value, which may be stored as "0". Then we update the existing sites with "0" and also default to "0" on new field instance.
+++ b/core/modules/comment/src/CommentViewBuilder.php
@@ -102,7 +108,7 @@ public function buildComponents(array &$build, array $entities, array $displays,
- if ($comment_indent > $current_indent) {
+ if ($comment_indent > $current_indent && $comment_indent <= $thread_depth) {
@@ -114,6 +120,12 @@ public function buildComponents(array &$build, array $entities, array $displays,
+ // Adjust indentation relative to the defined thread depth.
+ if ($comment_indent > $thread_depth) {
+ $indent_adjustment = $comment_indent - $thread_depth;
+ $build[$id]['#comment_indent'] -= $indent_adjustment;
+ $current_indent -= $indent_adjustment;
+ }
I disagree with the approach. We should not flatten the depth to the max thread depth. Instead we should hack into access control and deny access to reply when the comment has the max depth. Meaning also that the Reply link will disappear.
+++ b/core/modules/comment/tests/src/Functional/Update/CommentUpdateTest.php
@@ -71,4 +72,49 @@ public function testPublishedEntityKey() {
+ $this->assertNotEmpty($results, t('Unable to grab existing comment field configs or none exist.'));
...
+ $this->assertArrayNotHasKey('thread_depth', $settings, t('thread_depth setting should not exist.'));
...
+ $this->assertNotEmpty($results, t('Unable to grab existing comment field configs or none exist.'));
...
+ $this->assertArrayHasKey('thread_depth', $settings, t('thread_depth setting should exist.'));
+ $this->assertEquals(CommentManagerInterface::COMMENT_MAX_THREAD_DEPTH, $settings['thread_depth'], t('thread_depth setting should be set to max value'));
You can omit assertion messages. But if you still want to keep them, don't translate them.
Had some more thoughts on #33.4 and I think we can offer a field configuration option. A site builder will be able to chose between allowing replying on the same level as the parent comment or totally disable the reply when the maximum depth is hit. Still needs tests.
Now site builders are able to configure each comment field whether replying to the deepest comment is allowed. If allowed, the reply will be displayed with the same indent as the parent comment. If not allowed, then replies are totally denied.
OK, fixed passing $sandbox by reference for 9.2.x. Thinking more on this... this is hard to be cough by the update test if the config being tested is in the first batch, because not passing $sandbox by reference will always run only the first batch. We should trick somehow the update test to limit the batch size to 1. In this way it would be more easy to detect this bug. Or better adding a Drupal Coder rule to check is the var is passed by reference?
The code looks pretty good, but I did some extensive testing and found 2 bugs:
--- a/core/modules/comment/src/CommentAccessControlHandler.php
+++ b/core/modules/comment/src/CommentAccessControlHandler.php
protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
+ // Forbid if this reply, to a threaded comment, is about to exceed the
+ // maximum thread depth.
+ if (isset($context['commented_entity']) && isset($context['parent_comment'])) {
+ // ...
+ }
return AccessResult::allowedIfHasPermission($account, 'post comments');
There is a bug here when the thread depth limit is set to 1 and the creation of child comments is denied. In this case it is not allowed to reply to root level comments, but this initial if statement bypasses the access check if $context['parent_comment'] is empty.
Root level comments do not have a parent comment, so this means that for root level comments the user will always be allowed access to create a child comment.
It's probably a good idea to add a test to ensure that when the depth level is set to 1 and the mode is set to THREAD_DEPTH_REPLY_MODE_DENY that the comments do not include a "Reply" link.
--- a/core/modules/comment/src/CommentViewBuilder.php
+++ b/core/modules/comment/src/CommentViewBuilder.php
+ // Compute the comment maximum indent if any.
+ $max_indent = NULL;
+ if ($commented_entity) {
+ // The maximum indent could determined only on non-orphan comments.
+ $thread_limit_settings = $entity->getCommentedEntity()
+ ->getFieldDefinition($entity->getFieldName())
+ ->getSetting('thread_limit');
+ $max_indent = $thread_limit_settings['mode'] === CommentItemInterface::THREAD_DEPTH_REPLY_MODE_ALLOW ? $thread_limit_settings['depth'] - 1 : NULL;
+ }
There is a functional disparity between the 2 different reply modes in this section. This is trying to "fix" the comment depths so that comments that are "deeper than allowed" appear on the same level as the parent comment. However since this is limited to the reply mode THREAD_DEPTH_REPLY_MODE_ALLOW I was able to get a comment thread to show up that was deeper than allowed by following these steps:
Create a comment field and configure it with a max depth of 2 and allowing child replies.
Create a long comment thread of minimum 5 comments, by always replying to the last comment.
Observe that the comment thread is shown only up to depth 2 as is expected.
Edit the comment field configuration and change toggle the reply mode to deny any child comments.
Reload the page: now the comment thread is shown up to a depth of 5. This is not expected since the maximum depth is 2.
I think the right solution is to also allow "fixing" the depth when the reply mode is set to THREAD_DEPTH_REPLY_MODE_DENY.
@pfrenssen thank you for your detailed review. The changes are in the merge request.
#50.1: There's now logic of having the maximum depth < 2. That would be a flat list. On UI, a user cannot enter a depth < 2. On API I've used assert() to do the check.
#50.2: You're right. While fixing this point, I've noticed that, in #48, I've broken the "threaded with no limit" mode. No test complained, so I've added regression testing coverage.
I wanted to practice working with merge requests so I merged in the latest changes from the base branch, but now there is a failure regarding the composer lock file checksum, which doesn't make much sense since this MR doesn't change any dependencies. I am suspecting that the hash is also incorrect in 9.2.x but the latest test is green. Strange. I don't think it looks like we can solve this inside this issue though.
I have just 2 very small remarks. One is to change the data type of a parameter in a test helper method, and a minor nit in a comment. Apart from these this looks good to go from me.
I figured out that in recent D9.5.2 some code from recent comment patches is already present, so I create a patch for it. If somebody needs a complete patch for version 9.5.x(PHP 8 .1).
Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.
Comments
Comment #2
mroycroft commentedAttached proposed patch.
Comment #3
mroycroft commentedComment #5
mroycroft commentedOops, forgot the schema change. Attached updated patch and interdiff.
Comment #6
mroycroft commentedComment #10
nick.james commentedComment #11
nick.james commentedComment #12
nick.james commentedComment #13
jhedstromComment #14
jhedstromSince this adds an update hook, the upgrade path needs to be tested. Check out
Drupal\Tests\comment\Functional\Update\CommentUpdateTest, as I think a new test method can just be added to that, and verify that the settings are indeed updated.The max thread depth should probably be a constant on the
CommentInterfaceinstead of hard-coding the number wherever it's used.Comment #15
nick.james commentedComment #16
nick.james commentedComment #18
nick.james commentedComment #19
nick.james commentedComment #20
nick.james commentedComment #21
jhedstromJust a few minor tweaks/questions:
With the update hook, and the default value above, shouldn't this always be set now?
I think an assert that these
$resultsare non-empty would be valuable. Otherwise, here, and below, if for whatever reason it didn't load any comments, none of the assertions in the foreach loops would run.Comment #22
nick.james commentedComment #23
nick.james commentedComment #26
kwadz commentedIs there something missing to include the patch in the next release?
Comment #28
maticb commented#22 works fine, but you should fix the null warning on line 119 in CommentItem.php: '#default_value' => $settings['thread_depth'] ?? 0,
(I added ?? 0)
Comment #29
thronedigital commentedbump
Comment #31
jax commentedThis only happens if you don't run the update_N hook since that hook should populate the setting for the existing fields.
The patch has in CommentViewBuilder.php:
followed by some additional lines in the else. Wouldn't it be easier to just do:
and leave the existing if/else alone?
Comment #33
claudiu.cristeaThe update number needs... update :)
This not the proper way to update a config entity. Please apply https://www.drupal.org/node/2949630.
Not a very big fan of settings a hard limit or suggesting a value. What if existing sites went beyond this value? I would rather allow a "not limited" value, which may be stored as "0". Then we update the existing sites with "0" and also default to "0" on new field instance.
I disagree with the approach. We should not flatten the depth to the max thread depth. Instead we should hack into access control and deny access to reply when the comment has the max depth. Meaning also that the Reply link will disappear.
You can omit assertion messages. But if you still want to keep them, don't translate them.
Comment #34
munish.kumar commentedHi,
I am picking this issue and working on the #33 feedback.
Thanks,
Comment #35
claudiu.cristeaFixing #33.
Comment #36
claudiu.cristeaUnfortunately we cannot switch to an "access based" approach (#33.4) because the access is not properly checked. See #2879087: Use comment access handler instead of hardcoding permissions to find out why. I will block this issue on #2879087: Use comment access handler instead of hardcoding permissions .
Fixed #33.1, 2, 3 and 5. Posting the partial work.
Comment #37
claudiu.cristeaPostponing on #2879087: Use comment access handler instead of hardcoding permissions
Comment #39
claudiu.cristeaThe #2879087: Use comment access handler instead of hardcoding permissions blocker depends also on #2886800: EntityAccessControlHandler::createAccess() returns false positive cache hits because it ignores context.
Will work on top of #2879087: Use comment access handler instead of hardcoding permissions to advance with this.
Comment #40
claudiu.cristeaFor now just rerolled and provided a patch on top of #2879087: Use comment access handler instead of hardcoding permissions for testing purposes.
Comment #41
claudiu.cristeaHad some more thoughts on #33.4 and I think we can offer a field configuration option. A site builder will be able to chose between allowing replying on the same level as the parent comment or totally disable the reply when the maximum depth is hit. Still needs tests.
Comment #42
claudiu.cristeaChanges:
Remaining tasks:
Comment #43
claudiu.cristeaComment #44
claudiu.cristeaChanges:
commented_entityis already in context when replying.Comment #45
claudiu.cristeaTo Whom It May Concern: Here's an unofficial version of #44 to be used w/ Drupal 8.9.x.
Comment #46
claudiu.cristeaOuch, bad merge.
The patch to be reviewed is #44.
Comment #47
claudiu.cristeaOh!
$sandboxshould be always passed by reference in update & post-update scripts.Comment #48
claudiu.cristeaOK, fixed passing
$sandboxby reference for 9.2.x. Thinking more on this... this is hard to be cough by the update test if the config being tested is in the first batch, because not passing$sandboxby reference will always run only the first batch. We should trick somehow the update test to limit the batch size to 1. In this way it would be more easy to detect this bug. Or better adding a Drupal Coder rule to check is the var is passed by reference?Comment #49
claudiu.cristeaAdded #3181654: Check that $sandbox is always passed by reference in (post)update functions as Drupal Coder followup
Comment #50
pfrenssenThe code looks pretty good, but I did some extensive testing and found 2 bugs:
There is a bug here when the thread depth limit is set to 1 and the creation of child comments is denied. In this case it is not allowed to reply to root level comments, but this initial if statement bypasses the access check if
$context['parent_comment']is empty.Root level comments do not have a parent comment, so this means that for root level comments the user will always be allowed access to create a child comment.
It's probably a good idea to add a test to ensure that when the depth level is set to 1 and the mode is set to
THREAD_DEPTH_REPLY_MODE_DENYthat the comments do not include a "Reply" link.There is a functional disparity between the 2 different reply modes in this section. This is trying to "fix" the comment depths so that comments that are "deeper than allowed" appear on the same level as the parent comment. However since this is limited to the reply mode
THREAD_DEPTH_REPLY_MODE_ALLOWI was able to get a comment thread to show up that was deeper than allowed by following these steps:I think the right solution is to also allow "fixing" the depth when the reply mode is set to
THREAD_DEPTH_REPLY_MODE_DENY.Comment #52
claudiu.cristea@pfrenssen thank you for your detailed review. The changes are in the merge request.
#50.1: There's now logic of having the maximum depth < 2. That would be a flat list. On UI, a user cannot enter a depth < 2. On API I've used
assert()to do the check.#50.2: You're right. While fixing this point, I've noticed that, in #48, I've broken the "threaded with no limit" mode. No test complained, so I've added regression testing coverage.
Comment #53
pfrenssenI wanted to practice working with merge requests so I merged in the latest changes from the base branch, but now there is a failure regarding the composer lock file checksum, which doesn't make much sense since this MR doesn't change any dependencies. I am suspecting that the hash is also incorrect in 9.2.x but the latest test is green. Strange. I don't think it looks like we can solve this inside this issue though.
I have just 2 very small remarks. One is to change the data type of a parameter in a test helper method, and a minor nit in a comment. Apart from these this looks good to go from me.
Comment #54
claudiu.cristeaMR remarks addressed
Comment #55
pfrenssenThanks! This looks good to me, but we need to wait for #2879087: Use comment access handler instead of hardcoding permissions to be merged before this can be set to RTBC. Postponing on that issue.
Comment #58
pfrenssenI rebased the main MR onto 9.4.x and have made a copy of the original branch available as
2786587-thread-depth-limit-9.2.x.Since the dynamically generated patches will now only apply to 9.4.x, here are backported patches for older versions of Drupal.
Comment #63
evonasek commentedI figured out that in recent D9.5.2 some code from recent comment patches is already present, so I create a patch for it. If somebody needs a complete patch for version 9.5.x(PHP 8 .1).
Comment #64
evonasek commentedComment #65
evonasek commentedComment #68
evonasek commentedD10.1.5 patch
Comment #69
evonasek commentedThe previous file is not correct. D10.x
Comment #70
evonasek commentedFixed version v3
Comment #71
paintingguy commentedRight on! This is a much needed option for the comments. Thank you !
How do I add this for D9?
Comment #75
evonasek commentedD10.3.1 patch
Comment #77
liam morlandI have rebased the merge requests in #73 and #74.
Comment #78
evonasek commentedComment #79
evonasek commentedComment #80
jhuhta commentedRebased both branches. For 11.x, #3483599: Convert all procedural hook implementations to Hook classes (I wasn't familiar with) forced me to move a change from comment.module to src/Hook/CommentHooks.php. Hopefully it's ok now.
I'm not sure if the patches above contain all the same changes.
Comment #83
saidatomGreat! Looks good.
Comment #84
smustgrave commentedThe PP in the title actually means it should be postponed and seems postponed on #2879087: Use comment access handler instead of hardcoding permissions from #36. Once that lands this ticket will need an issue summary update and many of these MRs closed.
Comment #85
claudiu.cristeaHide patches
Comment #96
evonasek commentedD10.5.6