diff --git a/core/modules/tracker/src/Controller/TrackerController.php b/core/modules/tracker/src/Controller/TrackerController.php index aeb65755ee..cf0df84b0d 100644 --- a/core/modules/tracker/src/Controller/TrackerController.php +++ b/core/modules/tracker/src/Controller/TrackerController.php @@ -68,7 +68,7 @@ class TrackerController extends ControllerBase { * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager * The entity type manager. */ - public function __construct(Connection $database, Connection $databaseReplica, CommentStatisticsInterface $commentStatistics, DateFormatterInterface $dateFormatter, EntityTypeManagerInterface $entityTypeManager) { + public function __construct(Connection $database, Connection $databaseReplica, CommentStatisticsInterface $commentStatistics = NULL, DateFormatterInterface $dateFormatter, EntityTypeManagerInterface $entityTypeManager) { $this->database = $database; $this->databaseReplica = $databaseReplica; $this->commentStatistics = $commentStatistics; @@ -81,10 +81,15 @@ public function __construct(Connection $database, Connection $databaseReplica, C * {@inheritdoc} */ public static function create(ContainerInterface $container) { + $comment_service = NULL; + if (\Drupal::hasService('comment.statistics')) { + $comment_service = $container->get('comment.statistics'); + } + return new static( $container->get('database'), $container->get('database.replica'), - $container->get('comment.statistics'), + $comment_service, $container->get('date.formatter'), $container->get('entity_type.manager') ); @@ -141,6 +146,11 @@ public function buildContent(UserInterface $user = NULL) { ->addMetaData('base_table', 'tracker_node'); } + $comment_installed = FALSE; + if (isset($this->commentStatistics)) { + $comment_installed = TRUE; + } + // This array acts as a placeholder for the data selected later // while keeping the correct order. $tracker_data = $query @@ -160,24 +170,26 @@ public function buildContent(UserInterface $user = NULL) { $nodes = $this->nodeStorage->loadMultiple(array_keys($tracker_data)); // Enrich the node data. - $result = $this->commentStatistics->read($nodes, 'node', FALSE); - foreach ($result as $statistics) { - // The node ID may not be unique; there can be multiple comment fields. - // Make comment_count the total of all comments. - $nid = $statistics->entity_id; - if (empty($nodes[$nid]->comment_count) - || !is_numeric($tracker_data[$nid]->comment_count)) { - $tracker_data[$nid]->comment_count = $statistics->comment_count; - } - else { - $tracker_data[$nid]->comment_count += $statistics->comment_count; - } - // Make the last comment timestamp reflect the latest comment. - if (!isset($tracker_data[$nid]->last_comment_timestamp)) { - $tracker_data[$nid]->last_comment_timestamp = $statistics->last_comment_timestamp; - } - else { - $tracker_data[$nid]->last_comment_timestamp = max($tracker_data[$nid]->last_comment_timestamp, $statistics->last_comment_timestamp); + if ($comment_installed) { + $result = $this->commentStatistics->read($nodes, 'node', FALSE); + foreach ($result as $statistics) { + // The node ID may not be unique; there can be multiple comment fields. + // Make comment_count the total of all comments. + $nid = $statistics->entity_id; + if (empty($nodes[$nid]->comment_count) + || !is_numeric($tracker_data[$nid]->comment_count)) { + $tracker_data[$nid]->comment_count = $statistics->comment_count; + } + else { + $tracker_data[$nid]->comment_count += $statistics->comment_count; + } + // Make the last comment timestamp reflect the latest comment. + if (!isset($tracker_data[$nid]->last_comment_timestamp)) { + $tracker_data[$nid]->last_comment_timestamp = $statistics->last_comment_timestamp; + } + else { + $tracker_data[$nid]->last_comment_timestamp = max($tracker_data[$nid]->last_comment_timestamp, $statistics->last_comment_timestamp); + } } } @@ -205,11 +217,6 @@ public function buildContent(UserInterface $user = NULL) { '#account' => $owner, ], ], - 'comments' => [ - 'class' => ['comments'], - 'data' => $tracker_data[$node->id()]->comment_count ?? 0, - 'data-history-node-last-comment-timestamp' => $tracker_data[$node->id()]->last_comment_timestamp ?? 0, - ], 'last updated' => [ 'data' => t('@time ago', [ '@time' => $this->dateFormatter->formatTimeDiffSince($last_activity), @@ -217,6 +224,17 @@ public function buildContent(UserInterface $user = NULL) { ], ]; + if ($comment_installed) { + $comment_row = [ + 'comments' => [ + 'class' => ['comments'], + 'data' => $tracker_data[$node->id()]->comment_count ?? 0, + 'data-history-node-last-comment-timestamp' => $tracker_data[$node->id()]->last_comment_timestamp ?? 0, + ], + ]; + $row = array_slice($row, 0, 3) + $comment_row + array_slice($row, 3); + } + $rows[] = $row; // Add node and node owner to cache tags. @@ -236,12 +254,19 @@ public function buildContent(UserInterface $user = NULL) { $this->t('Type'), $this->t('Title'), $this->t('Author'), - $this->t('Comments'), $this->t('Last updated'), ], '#type' => 'table', '#empty' => $this->t('No content available.'), ]; + + if ($comment_installed) { + $comment_header = [$this->t('Comments')]; + $beginning = array_slice($page['tracker']['#header'], 0, 3); + $end = array_slice($page['tracker']['#header'], 3); + $page['tracker']['#header'] = array_merge($beginning, $comment_header, $end); + } + $page['pager'] = [ '#type' => 'pager', '#weight' => 10, diff --git a/core/modules/tracker/tests/src/Functional/TrackerNodeAccessTest.php b/core/modules/tracker/tests/src/Functional/TrackerNodeAccessTest.php index 58dbd26690..ffc4c3ee91 100644 --- a/core/modules/tracker/tests/src/Functional/TrackerNodeAccessTest.php +++ b/core/modules/tracker/tests/src/Functional/TrackerNodeAccessTest.php @@ -4,6 +4,7 @@ use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface; use Drupal\comment\Tests\CommentTestTrait; +use Drupal\field\Entity\FieldStorageConfig; use Drupal\node\Entity\NodeType; use Drupal\Tests\BrowserTestBase; @@ -104,6 +105,8 @@ public function testTrackerNodeAccess() { $this->drupalGet('user/' . $access_user->id() . '/activity'); $this->assertSession()->pageTextContains($private_node->getTitle()); $this->assertSession()->pageTextContains($public_node->getTitle()); + // Comments column displayed. + $this->assertSession()->pageTextContains('Comments'); // User without access should not see private node. $this->drupalLogin($no_access_user); @@ -113,6 +116,20 @@ public function testTrackerNodeAccess() { $this->drupalGet('user/' . $access_user->id() . '/activity'); $this->assertSession()->pageTextNotContains($private_node->getTitle()); $this->assertSession()->pageTextContains($public_node->getTitle()); + // Ensure module pages works when comment module uninstalled. + $field = FieldStorageConfig::loadByName('node', 'comment'); + $field->delete(); + field_purge_batch(10); + $this->container->get('module_installer')->uninstall(['comment']); + $this->drupalLogin($access_user); + $this->drupalGet('activity'); + $this->assertSession()->pageTextContains($private_node->getTitle()); + // Comments column hidden. + $this->assertSession()->pageTextNotContains('Comments'); + $this->drupalGet('user/' . $access_user->id() . '/activity'); + $this->assertSession()->pageTextContains($private_node->getTitle()); + // Comments column hidden. + $this->assertSession()->pageTextNotContains('Comments'); } } diff --git a/core/modules/tracker/tests/src/Functional/TrackerTest.php b/core/modules/tracker/tests/src/Functional/TrackerTest.php index 1cb6cd8a79..e499ec19ec 100644 --- a/core/modules/tracker/tests/src/Functional/TrackerTest.php +++ b/core/modules/tracker/tests/src/Functional/TrackerTest.php @@ -2,14 +2,10 @@ namespace Drupal\Tests\tracker\Functional; -use Drupal\comment\CommentInterface; -use Drupal\comment\Tests\CommentTestTrait; use Drupal\Core\Cache\Cache; use Drupal\Core\Database\Database; use Drupal\Core\EventSubscriber\MainContentViewSubscriber; use Drupal\Core\Session\AccountInterface; -use Drupal\field\Entity\FieldStorageConfig; -use Drupal\node\Entity\Node; use Drupal\Tests\BrowserTestBase; use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait; @@ -21,7 +17,6 @@ */ class TrackerTest extends BrowserTestBase { - use CommentTestTrait; use AssertPageCacheContextsAndTagsTrait; /** @@ -37,6 +32,13 @@ class TrackerTest extends BrowserTestBase { 'node_test', ]; + /** + * Permissions to give to test users. + * + * @var array + */ + protected $permissions = ['create page content']; + /** * {@inheritdoc} */ @@ -68,6 +70,8 @@ protected function setUp(): void { $this->user = $this->drupalCreateUser($permissions); $this->otherUser = $this->drupalCreateUser($permissions); $this->addDefaultCommentField('node', 'page'); + $this->user = $this->drupalCreateUser($this->permissions); + $this->otherUser = $this->drupalCreateUser($this->permissions); user_role_grant_permissions(AccountInterface::ANONYMOUS_ROLE, [ 'access content', 'access user profiles', @@ -98,6 +102,15 @@ public function testTrackerAll() { // Assert cache contexts, specifically the pager and node access contexts. $this->assertCacheContexts(['languages:language_interface', 'route', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.query_args.pagers:0', 'user.node_grants:view', 'user']); + $this->assertCacheContexts([ + 'languages:language_interface', + 'route', 'theme', + 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, + 'url.query_args.pagers:0', + 'user.node_grants:view', + 'user', + ] + ); // Assert cache tags for the action/tabs blocks, visible node, and node list // cache tag. $expected_tags = Cache::mergeTags($published->getCacheTags(), $published->getOwner()->getCacheTags()); @@ -126,21 +139,6 @@ public function testTrackerAll() { $published->delete(); $this->drupalGet('activity'); $this->assertSession()->pageTextNotContains($published->label()); - - // Test proper display of time on activity page when comments are disabled. - // Disable comments. - FieldStorageConfig::loadByName('node', 'comment')->delete(); - $node = $this->drupalCreateNode([ - // This title is required to trigger the custom changed time set in the - // node_test module. This is needed in order to ensure a sufficiently - // large 'time ago' interval that isn't numbered in seconds. - 'title' => 'testing_node_presave', - 'status' => 1, - ]); - - $this->drupalGet('activity'); - $this->assertSession()->pageTextContains($node->label()); - $this->assertSession()->pageTextContains(\Drupal::service('date.formatter')->formatTimeDiffSince($node->getChangedTime())); } /** @@ -148,48 +146,31 @@ public function testTrackerAll() { */ public function testTrackerUser() { $this->drupalLogin($this->user); - - $unpublished = $this->drupalCreateNode([ + $nodes = []; + $nodes['unpublished'] = $this->drupalCreateNode([ 'title' => $this->randomMachineName(8), 'uid' => $this->user->id(), 'status' => 0, ]); - $my_published = $this->drupalCreateNode([ + $nodes['my_published'] = $this->drupalCreateNode([ 'title' => $this->randomMachineName(8), 'uid' => $this->user->id(), 'status' => 1, - ]); - $other_published_no_comment = $this->drupalCreateNode([ - 'title' => $this->randomMachineName(8), - 'uid' => $this->otherUser->id(), - 'status' => 1, - ]); - $other_published_my_comment = $this->drupalCreateNode([ - 'title' => $this->randomMachineName(8), - 'uid' => $this->otherUser->id(), - 'status' => 1, - ]); - $comment = [ - 'subject[0][value]' => $this->randomMachineName(), - 'comment_body[0][value]' => $this->randomMachineName(20), - ]; - $this->drupalGet('comment/reply/node/' . $other_published_my_comment->id() . '/comment'); - $this->submitForm($comment, 'Save'); - + ]); $this->drupalGet('user/' . $this->user->id() . '/activity'); - $this->assertSession()->pageTextNotContains($unpublished->label()); - $this->assertSession()->pageTextContains($my_published->label()); - $this->assertSession()->pageTextNotContains($other_published_no_comment->label()); - $this->assertSession()->pageTextContains($other_published_my_comment->label()); - // Assert cache contexts. - $this->assertCacheContexts(['languages:language_interface', 'route', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.query_args.pagers:0', 'user', 'user.node_grants:view']); + $this->assertCacheContexts([ + 'languages:language_interface', + 'route', 'theme', + 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, + 'url.query_args.pagers:0', + 'user', + 'user.node_grants:view', + ] + ); // Assert cache tags for the visible nodes (including owners) and node list // cache tag. - $expected_tags = Cache::mergeTags($my_published->getCacheTags(), $my_published->getOwner()->getCacheTags()); - $expected_tags = Cache::mergeTags($expected_tags, $other_published_my_comment->getCacheTags()); - $expected_tags = Cache::mergeTags($expected_tags, $other_published_my_comment->getOwner()->getCacheTags()); - // Because the 'user.permissions' cache context is being optimized away. + $expected_tags = Cache::mergeTags($nodes['my_published']->getCacheTags(), $nodes['my_published']->getOwner()->getCacheTags());// Because the 'user.permissions' cache context is being optimized away. $role_tags = []; foreach ($this->user->getRoles() as $rid) { $role_tags[] = "config:user.role.$rid"; @@ -210,26 +191,20 @@ public function testTrackerUser() { $expected_tags = Cache::mergeTags($expected_tags, $additional_tags); $this->assertCacheTags($expected_tags); - $this->assertCacheContexts(['languages:language_interface', 'route', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'url.query_args.pagers:0', 'user', 'user.node_grants:view']); - - $this->assertSession()->linkExists($my_published->label()); - $this->assertSession()->linkNotExists($unpublished->label()); - // Verify that title and tab title have been set correctly. - $this->assertSession()->pageTextContains('Activity'); - $this->assertSession()->titleEquals($this->user->getAccountName() . ' | Drupal'); - - // Verify that unpublished comments are removed from the tracker. - $admin_user = $this->drupalCreateUser([ - 'post comments', - 'administer comments', - 'access user profiles', - ]); - $this->drupalLogin($admin_user); - $this->drupalGet('comment/1/edit'); - $this->submitForm(['status' => CommentInterface::NOT_PUBLISHED], 'Save'); - $this->drupalGet('user/' . $this->user->id() . '/activity'); - $this->assertSession()->pageTextNotContains($other_published_my_comment->label()); - + $this->assertCacheContexts([ + 'languages:language_interface', + 'route', + 'theme', + 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, + 'url.query_args.pagers:0', + 'user', + 'user.node_grants:view', + ] + ); + + $this->assertSession()->linkExists($nodes['my_published']->label()); + $this->assertSession()->linkNotExists($nodes['unpublished']->label()); + // Test escaping of title on user's tracker tab. \Drupal::service('module_installer')->install(['user_hooks_test']); Cache::invalidateTags(['rendered']); @@ -258,112 +233,11 @@ public function testTrackerHistoryMetadata() { // Verify that the history metadata is present. $this->drupalGet('activity'); - $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->getChangedTime()); - $this->drupalGet('activity/' . $this->user->id()); - $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->getChangedTime()); - $this->drupalGet('user/' . $this->user->id() . '/activity'); - $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->getChangedTime()); - - // Add a comment to the page, make sure it is created after the node by - // sleeping for one second, to ensure the last comment timestamp is - // different from before. - $comment = [ - 'subject[0][value]' => $this->randomMachineName(), - 'comment_body[0][value]' => $this->randomMachineName(20), - ]; - sleep(1); - $this->drupalGet('comment/reply/node/' . $node->id() . '/comment'); - $this->submitForm($comment, 'Save'); - // Reload the node so that comment.module's hook_node_load() - // implementation can set $node->last_comment_timestamp for the freshly - // posted comment. - $node = Node::load($node->id()); - - // Verify that the history metadata is updated. - $this->drupalGet('activity'); - $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->get('comment')->last_comment_timestamp); + $this->assertHistoryMetadata($node->id(), $node->getChangedTime()); $this->drupalGet('activity/' . $this->user->id()); - $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->get('comment')->last_comment_timestamp); + $this->assertHistoryMetadata($node->id(), $node->getChangedTime()); $this->drupalGet('user/' . $this->user->id() . '/activity'); - $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->get('comment')->last_comment_timestamp); - - // Log out, now verify that the metadata is still there, but the library is - // not. - $this->drupalLogout(); - $this->drupalGet('activity'); - $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->get('comment')->last_comment_timestamp, FALSE); - $this->drupalGet('user/' . $this->user->id() . '/activity'); - $this->assertHistoryMetadata($node->id(), $node->getChangedTime(), $node->get('comment')->last_comment_timestamp, FALSE); - } - - /** - * Tests for ordering on a users tracker listing when comments are posted. - */ - public function testTrackerOrderingNewComments() { - $this->drupalLogin($this->user); - - $node_one = $this->drupalCreateNode([ - 'title' => $this->randomMachineName(8), - ]); - - $node_two = $this->drupalCreateNode([ - 'title' => $this->randomMachineName(8), - ]); - - // Now get otherUser to track these pieces of content. - $this->drupalLogin($this->otherUser); - - // Add a comment to the first page. - $comment = [ - 'subject[0][value]' => $this->randomMachineName(), - 'comment_body[0][value]' => $this->randomMachineName(20), - ]; - $this->drupalGet('comment/reply/node/' . $node_one->id() . '/comment'); - $this->submitForm($comment, 'Save'); - - // If the comment is posted in the same second as the last one then Drupal - // can't tell the difference, so we wait one second here. - sleep(1); - - // Add a comment to the second page. - $comment = [ - 'subject[0][value]' => $this->randomMachineName(), - 'comment_body[0][value]' => $this->randomMachineName(20), - ]; - $this->drupalGet('comment/reply/node/' . $node_two->id() . '/comment'); - $this->submitForm($comment, 'Save'); - - // We should at this point have in our tracker for otherUser: - // 1. node_two - // 2. node_one - // Because that's the reverse order of the posted comments. - - // Now we're going to post a comment to node_one which should jump it to the - // top of the list. - - $this->drupalLogin($this->user); - // If the comment is posted in the same second as the last one then Drupal - // can't tell the difference, so we wait one second here. - sleep(1); - - // Add a comment to the second page. - $comment = [ - 'subject[0][value]' => $this->randomMachineName(), - 'comment_body[0][value]' => $this->randomMachineName(20), - ]; - $this->drupalGet('comment/reply/node/' . $node_one->id() . '/comment'); - $this->submitForm($comment, 'Save'); - - // Switch back to the otherUser and assert that the order has swapped. - $this->drupalLogin($this->otherUser); - $this->drupalGet('user/' . $this->otherUser->id() . '/activity'); - // This is a cheeky way of asserting that the nodes are in the right order - // on the tracker page. - // It's almost certainly too brittle. - $pattern = '/' . preg_quote($node_one->getTitle()) . '.+' . preg_quote($node_two->getTitle()) . '/s'; - // Verify that the most recent comment on node appears at the top of - // tracker. - $this->assertSession()->responseMatches($pattern); + $this->assertHistoryMetadata($node->id(), $node->getChangedTime()); } /** @@ -382,15 +256,6 @@ public function testTrackerCronIndexing() { $nodes[$i] = $this->drupalCreateNode($edits[$i]); } - // Add a comment to the last node as other user. - $this->drupalLogin($this->otherUser); - $comment = [ - 'subject[0][value]' => $this->randomMachineName(), - 'comment_body[0][value]' => $this->randomMachineName(20), - ]; - $this->drupalGet('comment/reply/node/' . $nodes[3]->id() . '/comment'); - $this->submitForm($comment, 'Save'); - // Create an unpublished node. $unpublished = $this->drupalCreateNode([ 'title' => $this->randomMachineName(8), @@ -399,7 +264,21 @@ public function testTrackerCronIndexing() { $this->drupalGet('activity'); $this->assertSession()->responseNotContains($unpublished->label()); + // Run the tests. + $this->doTestTrackerCronIndexing($nodes); + } + /** + * Runs assertions for testTrackerCronIndexing(). + * + * This has been moved into a separate method to ease tests of the sub-method + * \Drupal\Tests\tracker\Functional\TrackerCommentTest::testTrackerCronIndexing() + * and reduce code duplication. + * + * @param \Drupal\node\Entity\Node[] $nodes + * The created nodes to test. + */ + protected function doTestTrackerCronIndexing(array $nodes) { // Start indexing backwards from node 4. \Drupal::state()->set('tracker.index_nid', 4); @@ -427,6 +306,8 @@ public function testTrackerCronIndexing() { // Assert that all node titles are displayed. foreach ($nodes as $i => $node) { $this->assertSession()->pageTextContains($node->label()); + // Run the tests. + $this->doTestTrackerCronIndexing($nodes); } } @@ -484,11 +365,13 @@ public function testTrackerAdminUnpublish() { * * @internal */ - public function assertHistoryMetadata(int $node_id, int $node_timestamp, int $node_last_comment_timestamp, bool $library_is_present = TRUE): void { + public function assertHistoryMetadata(int $node_id, int $node_timestamp, int $node_last_comment_timestamp = NULL, bool $library_is_present = TRUE): void { $settings = $this->getDrupalSettings(); $this->assertSame($library_is_present, isset($settings['ajaxPageState']) && in_array('tracker/history', explode(',', $settings['ajaxPageState']['libraries'])), 'drupal.tracker-history library is present.'); $this->assertSession()->elementsCount('xpath', '//table/tbody/tr/td[@data-history-node-id="' . $node_id . '" and @data-history-node-timestamp="' . $node_timestamp . '"]', 1); - $this->assertSession()->elementsCount('xpath', '//table/tbody/tr/td[@data-history-node-last-comment-timestamp="' . $node_last_comment_timestamp . '"]', 1); + if (isset($node_last_comment_timestamp)) { + $this->assertSession()->elementsCount('xpath', '//table/tbody/tr/td[@data-history-node-last-comment-timestamp="' . $node_last_comment_timestamp . '"]', 1); + } } } diff --git a/core/modules/tracker/tests/src/Kernel/Migrate/d7/MigrateTrackerSettingsTest.php b/core/modules/tracker/tests/src/Kernel/Migrate/d7/MigrateTrackerSettingsTest.php index 48ad0da838..52b8ed7e42 100644 --- a/core/modules/tracker/tests/src/Kernel/Migrate/d7/MigrateTrackerSettingsTest.php +++ b/core/modules/tracker/tests/src/Kernel/Migrate/d7/MigrateTrackerSettingsTest.php @@ -10,6 +10,11 @@ */ class MigrateTrackerSettingsTest extends MigrateDrupalTestBase { + /** + * Modules to enable. + * + * @var array + */ protected static $modules = ['tracker']; /** diff --git a/core/modules/tracker/tracker.info.yml b/core/modules/tracker/tracker.info.yml index e51613d009..0d1b7fe9cc 100644 --- a/core/modules/tracker/tracker.info.yml +++ b/core/modules/tracker/tracker.info.yml @@ -5,6 +5,5 @@ lifecycle: deprecated lifecycle_link: 'https://www.drupal.org/about/core/policies/core-change-policies/deprecated-and-obsolete-modules-and-themes#s-activity-tracker' dependencies: - drupal:node - - drupal:comment package: Core version: VERSION diff --git a/core/modules/tracker/tracker.module b/core/modules/tracker/tracker.module index 8dbc5ac2f2..8b85bc8d1f 100644 --- a/core/modules/tracker/tracker.module +++ b/core/modules/tracker/tracker.module @@ -91,29 +91,30 @@ function tracker_cron() { // Insert the user-level data for the commenters (except if a commenter // is the node's author). - // Get unique user IDs via entityQueryAggregate because it's the easiest // database agnostic way. We don't actually care about the comments here // so don't add an aggregate field. - $result = \Drupal::entityQueryAggregate('comment') - ->accessCheck(FALSE) - ->condition('entity_type', 'node') - ->condition('entity_id', $node->id()) - ->condition('uid', $node->getOwnerId(), '<>') - ->condition('status', CommentInterface::PUBLISHED) - ->groupBy('uid') - ->execute(); - if ($result) { - $query = $connection->insert('tracker_user'); - foreach ($result as $row) { - $query->fields([ - 'uid' => $row['uid'], - 'nid' => $nid, - 'published' => CommentInterface::PUBLISHED, - 'changed' => $changed, - ]); + if (\Drupal::moduleHandler()->moduleExists('comment')) { + $result = \Drupal::entityQueryAggregate('comment') + ->accessCheck(FALSE) + ->condition('entity_type', 'node') + ->condition('entity_id', $node->id()) + ->condition('uid', $node->getOwnerId(), '<>') + ->condition('status', CommentInterface::PUBLISHED) + ->groupBy('uid') + ->execute(); + if ($result) { + $query = $connection->insert('tracker_user'); + foreach ($result as $row) { + $query->fields([ + 'uid' => $row['uid'], + 'nid' => $nid, + 'published' => CommentInterface::PUBLISHED, + 'changed' => $changed, + ]); + } + $query->execute(); } - $query->execute(); } // Note that we have indexed at least one node. @@ -263,11 +264,13 @@ function _tracker_add($nid, $uid, $changed) { * @todo Check if we should introduce 'language context' here, because the * callers may need different timestamps depending on the users' language? */ -function _tracker_calculate_changed($node) { +function _tracker_calculate_changed(NodeInterface $node) { $changed = $node->getChangedTime(); - $latest_comment = \Drupal::service('comment.statistics')->read([$node], 'node', FALSE); - if ($latest_comment && $latest_comment->last_comment_timestamp > $changed) { - $changed = $latest_comment->last_comment_timestamp; + if (\Drupal::hasService('comment.statistics')) { + $latest_comment = \Drupal::service('comment.statistics')->read([$node], 'node', FALSE); + if ($latest_comment && $latest_comment->last_comment_timestamp > $changed) { + $changed = $latest_comment->last_comment_timestamp; + } } return $changed; } @@ -321,7 +324,6 @@ function _tracker_remove($nid, $uid = NULL, $changed = NULL) { if ($tracker_node && $changed >= $tracker_node->changed) { // If we're here, the item being removed is *possibly* the item that // established the node's changed timestamp. - // We just have to recalculate things from scratch. $changed = _tracker_calculate_changed($node); diff --git a/core/modules/tracker/tracker.views.inc b/core/modules/tracker/tracker.views.inc index be15d57478..4422f4605f 100644 --- a/core/modules/tracker/tracker.views.inc +++ b/core/modules/tracker/tracker.views.inc @@ -157,7 +157,7 @@ function tracker_views_data() { * Implements hook_views_data_alter(). */ function tracker_views_data_alter(&$data) { - // Provide additional uid_touch handlers which are handled by tracker + // Provide additional uid_touch handlers which are handled by tracker. $data['node_field_data']['uid_touch_tracker'] = [ 'group' => t('Tracker - User'), 'title' => t('User posted or commented'),