updated core and modules

This commit is contained in:
Bachir Soussi Chiadmi
2017-09-09 16:27:51 +02:00
parent 027aa99b32
commit 41863f872c
7810 changed files with 318922 additions and 83631 deletions
@@ -1,5 +1,2 @@
access_log:
enabled: false
max_lifetime: 259200
count_content_views: 0
display_max_age: 3600
@@ -4,16 +4,6 @@ statistics.settings:
type: config_object
label: 'Statistics settings'
mapping:
access_log:
type: mapping
label: 'Access log settings'
mapping:
enabled:
type: boolean
label: 'Enable'
max_lifetime:
type: integer
label: 'Maximum lifetime'
count_content_views:
type: integer
label: 'Count content views'
@@ -0,0 +1,16 @@
id: statistics_settings
label: Statistics configuration
migration_tags:
- Drupal 6
- Drupal 7
source:
plugin: variable
variables:
- statistics_enable_access_log
- statistics_flush_accesslog_timer
- statistics_count_content_views
process:
'count_content_views': statistics_count_content_views
destination:
plugin: config
config_name: statistics.settings
@@ -0,0 +1,148 @@
<?php
namespace Drupal\statistics;
use Drupal\Core\Database\Connection;
use Drupal\Core\State\StateInterface;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Provides the default database storage backend for statistics.
*/
class NodeStatisticsDatabaseStorage implements StatisticsStorageInterface {
/**
* The database connection used.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* The state service.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* The request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* Constructs the statistics storage.
*
* @param \Drupal\Core\Database\Connection $connection
* The database connection for the node view storage.
* @param \Drupal\Core\State\StateInterface $state
* The state service.
*/
public function __construct(Connection $connection, StateInterface $state, RequestStack $request_stack) {
$this->connection = $connection;
$this->state = $state;
$this->requestStack = $request_stack;
}
/**
* {@inheritdoc}
*/
public function recordView($id) {
return (bool) $this->connection
->merge('node_counter')
->key('nid', $id)
->fields([
'daycount' => 1,
'totalcount' => 1,
'timestamp' => $this->getRequestTime(),
])
->expression('daycount', 'daycount + 1')
->expression('totalcount', 'totalcount + 1')
->execute();
}
/**
* {@inheritdoc}
*/
public function fetchViews($ids) {
$views = $this->connection
->select('node_counter', 'nc')
->fields('nc', ['totalcount', 'daycount', 'timestamp'])
->condition('nid', $ids, 'IN')
->execute()
->fetchAll();
foreach ($views as $id => $view) {
$views[$id] = new StatisticsViewsResult($view->totalcount, $view->daycount, $view->timestamp);
}
return $views;
}
/**
* {@inheritdoc}
*/
public function fetchView($id) {
$views = $this->fetchViews([$id]);
return reset($views);
}
/**
* {@inheritdoc}
*/
public function fetchAll($order = 'totalcount', $limit = 5) {
assert(in_array($order, ['totalcount', 'daycount', 'timestamp']), "Invalid order argument.");
return $this->connection
->select('node_counter', 'nc')
->fields('nc', ['nid'])
->orderBy($order, 'DESC')
->range(0, $limit)
->execute()
->fetchCol();
}
/**
* {@inheritdoc}
*/
public function deleteViews($id) {
return (bool) $this->connection
->delete('node_counter')
->condition('nid', $id)
->execute();
}
/**
* {@inheritdoc}
*/
public function resetDayCount() {
$statistics_timestamp = $this->state->get('statistics.day_timestamp') ?: 0;
if (($this->getRequestTime() - $statistics_timestamp) >= 86400) {
$this->state->set('statistics.day_timestamp', $this->getRequestTime());
$this->connection->update('node_counter')
->fields(['daycount' => 0])
->execute();
}
}
/**
* {@inheritdoc}
*/
public function maxTotalCount() {
$query = $this->connection->select('node_counter', 'nc');
$query->addExpression('MAX(totalcount)');
$max_total_count = (int)$query->execute()->fetchField();
return $max_total_count;
}
/**
* Get current request time.
*
* @return int
* Unix timestamp for current server request time.
*/
protected function getRequestTime() {
return $this->requestStack->getCurrentRequest()->server->get('REQUEST_TIME');
}
}
@@ -4,8 +4,14 @@ namespace Drupal\statistics\Plugin\Block;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\statistics\StatisticsStorageInterface;
/**
* Provides a 'Popular content' block.
@@ -15,17 +21,82 @@ use Drupal\Core\Session\AccountInterface;
* admin_label = @Translation("Popular content")
* )
*/
class StatisticsPopularBlock extends BlockBase {
class StatisticsPopularBlock extends BlockBase implements ContainerFactoryPluginInterface {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The entity repository service.
*
* @var \Drupal\Core\Entity\EntityRepositoryInterface
*/
protected $entityRepository;
/**
* The storage for statistics.
*
* @var \Drupal\statistics\StatisticsStorageInterface
*/
protected $statisticsStorage;
/**
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* Constructs an StatisticsPopularBlock object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
* The entity repository service
* @param \Drupal\statistics\StatisticsStorageInterface $statistics_storage
* The storage for statistics.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityRepositoryInterface $entity_repository, StatisticsStorageInterface $statistics_storage, RendererInterface $renderer) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entity_type_manager;
$this->entityRepository = $entity_repository;
$this->statisticsStorage = $statistics_storage;
$this->renderer = $renderer;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager'),
$container->get('entity.repository'),
$container->get('statistics.storage.node'),
$container->get('renderer')
);
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return array(
return [
'top_day_num' => 0,
'top_all_num' => 0,
'top_last_num' => 0
);
];
}
/**
@@ -40,29 +111,29 @@ class StatisticsPopularBlock extends BlockBase {
*/
public function blockForm($form, FormStateInterface $form_state) {
// Popular content block settings.
$numbers = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 40);
$numbers = array('0' => $this->t('Disabled')) + array_combine($numbers, $numbers);
$form['statistics_block_top_day_num'] = array(
$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 40];
$numbers = ['0' => $this->t('Disabled')] + array_combine($numbers, $numbers);
$form['statistics_block_top_day_num'] = [
'#type' => 'select',
'#title' => $this->t("Number of day's top views to display"),
'#default_value' => $this->configuration['top_day_num'],
'#options' => $numbers,
'#description' => $this->t('How many content items to display in "day" list.'),
);
$form['statistics_block_top_all_num'] = array(
];
$form['statistics_block_top_all_num'] = [
'#type' => 'select',
'#title' => $this->t('Number of all time views to display'),
'#default_value' => $this->configuration['top_all_num'],
'#options' => $numbers,
'#description' => $this->t('How many content items to display in "all time" list.'),
);
$form['statistics_block_top_last_num'] = array(
];
$form['statistics_block_top_last_num'] = [
'#type' => 'select',
'#title' => $this->t('Number of most recent views to display'),
'#default_value' => $this->configuration['top_last_num'],
'#options' => $numbers,
'#description' => $this->t('How many content items to display in "recently viewed" list.'),
);
];
return $form;
}
@@ -79,31 +150,67 @@ class StatisticsPopularBlock extends BlockBase {
* {@inheritdoc}
*/
public function build() {
$content = array();
$content = [];
if ($this->configuration['top_day_num'] > 0) {
$result = statistics_title_list('daycount', $this->configuration['top_day_num']);
if ($result) {
$content['top_day'] = node_title_list($result, $this->t("Today's:"));
$nids = $this->statisticsStorage->fetchAll('daycount', $this->configuration['top_day_num']);
if ($nids) {
$content['top_day'] = $this->nodeTitleList($nids, $this->t("Today's:"));
$content['top_day']['#suffix'] = '<br />';
}
}
if ($this->configuration['top_all_num'] > 0) {
$result = statistics_title_list('totalcount', $this->configuration['top_all_num']);
if ($result) {
$content['top_all'] = node_title_list($result, $this->t('All time:'));
$nids = $this->statisticsStorage->fetchAll('totalcount', $this->configuration['top_all_num']);
if ($nids) {
$content['top_all'] = $this->nodeTitleList($nids, $this->t('All time:'));
$content['top_all']['#suffix'] = '<br />';
}
}
if ($this->configuration['top_last_num'] > 0) {
$result = statistics_title_list('timestamp', $this->configuration['top_last_num']);
$content['top_last'] = node_title_list($result, $this->t('Last viewed:'));
$nids = $this->statisticsStorage->fetchAll('timestamp', $this->configuration['top_last_num']);
$content['top_last'] = $this->nodeTitleList($nids, $this->t('Last viewed:'));
$content['top_last']['#suffix'] = '<br />';
}
return $content;
}
/**
* Generates the ordered array of node links for build().
*
* @param int[] $nids
* An ordered array of node ids.
* @param string $title
* The title for the list.
*
* @return array
* A render array for the list.
*/
protected function nodeTitleList(array $nids, $title) {
$nodes = $this->entityTypeManager->getStorage('node')->loadMultiple($nids);
$items = [];
foreach ($nids as $nid) {
$node = $this->entityRepository->getTranslationFromContext($nodes[$nid]);
$item = [
'#type' => 'link',
'#title' => $node->getTitle(),
'#url' => $node->urlInfo('canonical'),
];
$this->renderer->addCacheableDependency($item, $node);
$items[] = $item;
}
return [
'#theme' => 'item_list__node',
'#items' => $items,
'#title' => $title,
'#cache' => [
'tags' => $this->entityTypeManager->getDefinition('node')->getListCacheTags(),
],
];
}
}
@@ -21,7 +21,7 @@ class StatisticsSettingsForm extends ConfigFormBase {
protected $moduleHandler;
/**
* Constructs a \Drupal\user\StatisticsSettingsForm object.
* Constructs a \Drupal\statistics\StatisticsSettingsForm object.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The factory for configuration objects.
@@ -65,17 +65,17 @@ class StatisticsSettingsForm extends ConfigFormBase {
$config = $this->config('statistics.settings');
// Content counter settings.
$form['content'] = array(
$form['content'] = [
'#type' => 'details',
'#title' => t('Content viewing counter settings'),
'#open' => TRUE,
);
$form['content']['statistics_count_content_views'] = array(
];
$form['content']['statistics_count_content_views'] = [
'#type' => 'checkbox',
'#title' => t('Count content views'),
'#default_value' => $config->get('count_content_views'),
'#description' => t('Increment a counter each time content is viewed.'),
);
];
return parent::buildForm($form, $form_state);
}
@@ -0,0 +1,90 @@
<?php
namespace Drupal\statistics;
/**
* Provides an interface defining Statistics Storage.
*
* Stores the views per day, total views and timestamp of last view
* for entities.
*/
interface StatisticsStorageInterface {
/**
* Count a entity view.
*
* @param int $id
* The ID of the entity to count.
*
* @return bool
* TRUE if the entity view has been counted.
*/
public function recordView($id);
/**
* Returns the number of times entities have been viewed.
*
* @param array $ids
* An array of IDs of entities to fetch the views for.
*
* @return \Drupal\statistics\StatisticsViewsResult[]
* An array of value objects representing the number of times each entity
* has been viewed. The array is keyed by entity ID. If an ID does not
* exist, it will not be present in the array.
*/
public function fetchViews($ids);
/**
* Returns the number of times a single entity has been viewed.
*
* @param int $id
* The ID of the entity to fetch the views for.
*
* @return \Drupal\statistics\StatisticsViewsResult|false
* If the entity exists, a value object representing the number of times if
* has been viewed. If it does not exist, FALSE is returned.
*/
public function fetchView($id);
/**
* Returns the number of times a entity has been viewed.
*
* @param string $order
* The counter name to order by:
* - 'totalcount' The total number of views.
* - 'daycount' The number of views today.
* - 'timestamp' The unix timestamp of the last view.
*
* @param int $limit
* The number of entity IDs to return.
*
* @return array
* An ordered array of entity IDs.
*/
public function fetchAll($order = 'totalcount', $limit = 5);
/**
* Delete counts for a specific entity.
*
* @param int $id
* The ID of the entity which views to delete.
*
* @return bool
* TRUE if the entity views have been deleted.
*/
public function deleteViews($id);
/**
* Reset the day counter for all entities once every day.
*/
public function resetDayCount();
/**
* Returns the highest 'totalcount' value.
*
* @return int
* The highest 'totalcount' value.
*/
public function maxTotalCount();
}
@@ -0,0 +1,60 @@
<?php
namespace Drupal\statistics;
/**
* Value object for passing statistic results.
*/
class StatisticsViewsResult {
/**
* @var int
*/
protected $totalCount;
/**
* @var int
*/
protected $dayCount;
/**
* @var int
*/
protected $timestamp;
public function __construct($total_count, $day_count, $timestamp) {
$this->totalCount = $total_count;
$this->dayCount = $day_count;
$this->timestamp = $timestamp;
}
/**
* Total number of times the entity has been viewed.
*
* @return int
*/
public function getTotalCount() {
return $this->totalCount;
}
/**
* Total number of times the entity has been viewed "today".
*
* @return int
*/
public function getDayCount() {
return $this->dayCount;
}
/**
* Timestamp of when the entity was last viewed.
*
* @return int
*/
public function getTimestamp() {
return $this->timestamp;
}
}
@@ -6,6 +6,9 @@ use Drupal\simpletest\WebTestBase;
/**
* Defines a base class for testing the Statistics module.
*
* @deprecated Scheduled for removal in Drupal 9.0.0.
* Use \Drupal\Tests\statistics\Functional\StatisticsTestBase instead.
*/
abstract class StatisticsTestBase extends WebTestBase {
@@ -14,7 +17,7 @@ abstract class StatisticsTestBase extends WebTestBase {
*
* @var array
*/
public static $modules = array('node', 'block', 'ban', 'statistics');
public static $modules = ['node', 'block', 'ban', 'statistics'];
/**
* User with permissions to ban IP's.
@@ -28,18 +31,18 @@ abstract class StatisticsTestBase extends WebTestBase {
// Create Basic page node type.
if ($this->profile != 'standard') {
$this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
}
// Create user.
$this->blockingUser = $this->drupalCreateUser(array(
$this->blockingUser = $this->drupalCreateUser([
'access administration pages',
'access site reports',
'ban IP addresses',
'administer blocks',
'administer statistics',
'administer users',
));
]);
$this->drupalLogin($this->blockingUser);
// Enable logging.
@@ -19,7 +19,7 @@ class IntegrationTest extends ViewTestBase {
*
* @var array
*/
public static $modules = array('statistics', 'statistics_test_views', 'node');
public static $modules = ['statistics', 'statistics_test_views', 'node'];
/**
* Stores the user object that accesses the page.
@@ -40,25 +40,24 @@ class IntegrationTest extends ViewTestBase {
*
* @var array
*/
public static $testViews = array('test_statistics_integration');
public static $testViews = ['test_statistics_integration'];
protected function setUp() {
parent::setUp();
ViewTestData::createTestViews(get_class($this), array('statistics_test_views'));
ViewTestData::createTestViews(get_class($this), ['statistics_test_views']);
// Create a new user for viewing nodes and statistics.
$this->webUser = $this->drupalCreateUser(array('access content', 'view post access counter'));
$this->webUser = $this->drupalCreateUser(['access content', 'view post access counter']);
// Create a new user for viewing nodes only.
$this->deniedUser = $this->drupalCreateUser(array('access content'));
$this->deniedUser = $this->drupalCreateUser(['access content']);
$this->drupalCreateContentType(array('type' => 'page'));
$this->node = $this->drupalCreateNode(array('type' => 'page'));
$this->drupalCreateContentType(['type' => 'page']);
$this->node = $this->drupalCreateNode(['type' => 'page']);
// Enable access logging.
// Enable counting of content views.
$this->config('statistics.settings')
->set('access_log.enabled', 1)
->set('count_content_views', 1)
->save();
@@ -75,8 +74,8 @@ class IntegrationTest extends ViewTestBase {
// @see \Drupal\statistics\Tests\StatisticsLoggingTest::testLogging().
global $base_url;
$stats_path = $base_url . '/' . drupal_get_path('module', 'statistics') . '/statistics.php';
$client = \Drupal::service('http_client_factory')->fromOptions(['config/curl', array(CURLOPT_TIMEOUT => 10)]);
$client->post($stats_path, array('form_params' => array('nid' => $this->node->id())));
$client = \Drupal::httpClient();
$client->post($stats_path, ['form_params' => ['nid' => $this->node->id()]]);
$this->drupalGet('test_statistics_integration');
$expected = statistics_get($this->node->id());
+3 -3
View File
@@ -8,8 +8,8 @@ configure: statistics.settings
dependencies:
- node
# Information added by Drupal.org packaging script on 2016-08-03
version: '8.1.8'
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
core: '8.x'
project: 'drupal'
datestamp: 1470233790
datestamp: 1502903957
+21 -14
View File
@@ -18,42 +18,42 @@ function statistics_uninstall() {
* Implements hook_schema().
*/
function statistics_schema() {
$schema['node_counter'] = array(
$schema['node_counter'] = [
'description' => 'Access statistics for {node}s.',
'fields' => array(
'nid' => array(
'fields' => [
'nid' => [
'description' => 'The {node}.nid for these statistics.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'totalcount' => array(
],
'totalcount' => [
'description' => 'The total number of times the {node} has been viewed.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'size' => 'big',
),
'daycount' => array(
],
'daycount' => [
'description' => 'The total number of times the {node} has been viewed today.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'size' => 'medium',
),
'timestamp' => array(
],
'timestamp' => [
'description' => 'The most recent time the {node} has been viewed.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
),
'primary key' => array('nid'),
);
],
],
'primary key' => ['nid'],
];
return $schema;
}
@@ -63,7 +63,7 @@ function statistics_schema() {
*/
function statistics_update_8001() {
if (!\Drupal::moduleHandler()->moduleExists('node')) {
if (\Drupal::service('module_installer')->uninstall(array('statistics'), TRUE)) {
if (\Drupal::service('module_installer')->uninstall(['statistics'], TRUE)) {
return 'The statistics module depends on the node module and has therefore been uninstalled.';
}
else {
@@ -79,3 +79,10 @@ function statistics_update_8002() {
// Set the new configuration setting for max age to the initial value.
\Drupal::configFactory()->getEditable('statistics.settings')->set('display_max_age', 3600)->save();
}
/**
* Remove access_log settings.
*/
function statistics_update_8300() {
\Drupal::configFactory()->getEditable('statistics.settings')->clear('access_log')->save();
}
+43 -50
View File
@@ -10,6 +10,7 @@ use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\node\NodeInterface;
use Drupal\statistics\StatisticsViewsResult;
/**
* Implements hook_help().
@@ -19,13 +20,13 @@ function statistics_help($route_name, RouteMatchInterface $route_match) {
case 'help.page.statistics':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Statistics module shows you how often content is viewed. This is useful in determining which pages of your site are most popular. For more information, see the <a href=":statistics_do">online documentation for the Statistics module</a>.', array(':statistics_do' => 'https://www.drupal.org/documentation/modules/statistics/')) . '</p>';
$output .= '<p>' . t('The Statistics module shows you how often content is viewed. This is useful in determining which pages of your site are most popular. For more information, see the <a href=":statistics_do">online documentation for the Statistics module</a>.', [':statistics_do' => 'https://www.drupal.org/documentation/modules/statistics/']) . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Displaying popular content') . '</dt>';
$output .= '<dd>' . t('The module includes a <em>Popular content</em> block that displays the most viewed pages today and for all time, and the last content viewed. To use the block, enable <em>Count content views</em> on the <a href=":statistics-settings">Statistics page</a>, and then you can enable and configure the block on the <a href=":blocks">Block layout page</a>.', array(':statistics-settings' => \Drupal::url('statistics.settings'), ':blocks' => (\Drupal::moduleHandler()->moduleExists('block')) ? \Drupal::url('block.admin_display') : '#')) . '</dd>';
$output .= '<dd>' . t('The module includes a <em>Popular content</em> block that displays the most viewed pages today and for all time, and the last content viewed. To use the block, enable <em>Count content views</em> on the <a href=":statistics-settings">Statistics page</a>, and then you can enable and configure the block on the <a href=":blocks">Block layout page</a>.', [':statistics-settings' => \Drupal::url('statistics.settings'), ':blocks' => (\Drupal::moduleHandler()->moduleExists('block')) ? \Drupal::url('block.admin_display') : '#']) . '</dd>';
$output .= '<dt>' . t('Page view counter') . '</dt>';
$output .= '<dd>' . t('The Statistics module includes a counter for each page that increases whenever the page is viewed. To use the counter, enable <em>Count content views</em> on the <a href=":statistics-settings">Statistics page</a>, and set the necessary <a href=":permissions">permissions</a> (<em>View content hits</em>) so that the counter is visible to the users.', array(':statistics-settings' => \Drupal::url('statistics.settings'), ':permissions' => \Drupal::url('user.admin_permissions', array(), array('fragment' => 'module-statistics')))) . '</dd>';
$output .= '<dd>' . t('The Statistics module includes a counter for each page that increases whenever the page is viewed. To use the counter, enable <em>Count content views</em> on the <a href=":statistics-settings">Statistics page</a>, and set the necessary <a href=":permissions">permissions</a> (<em>View content hits</em>) so that the counter is visible to the users.', [':statistics-settings' => \Drupal::url('statistics.settings'), ':permissions' => \Drupal::url('user.admin_permissions', [], ['fragment' => 'module-statistics'])]) . '</dd>';
$output .= '</dl>';
return $output;
@@ -40,7 +41,7 @@ function statistics_help($route_name, RouteMatchInterface $route_match) {
function statistics_node_view(array &$build, EntityInterface $node, EntityViewDisplayInterface $display, $view_mode) {
if (!$node->isNew() && $view_mode == 'full' && node_is_page($node) && empty($node->in_preview)) {
$build['#attached']['library'][] = 'statistics/drupal.statistics';
$settings = array('data' => array('nid' => $node->id()), 'url' => Url::fromUri('base:' . drupal_get_path('module', 'statistics') . '/statistics.php')->toString());
$settings = ['data' => ['nid' => $node->id()], 'url' => Url::fromUri('base:' . drupal_get_path('module', 'statistics') . '/statistics.php')->toString()];
$build['#attached']['drupalSettings']['statistics'] = $settings;
}
}
@@ -52,14 +53,14 @@ function statistics_node_links_alter(array &$links, NodeInterface $entity, array
if ($context['view_mode'] != 'rss') {
$links['#cache']['contexts'][] = 'user.permissions';
if (\Drupal::currentUser()->hasPermission('view post access counter')) {
$statistics = statistics_get($entity->id());
$statistics = \Drupal::service('statistics.storage.node')->fetchView($entity->id());
if ($statistics) {
$statistics_links['statistics_counter']['title'] = \Drupal::translation()->formatPlural($statistics['totalcount'], '1 view', '@count views');
$links['statistics'] = array(
$statistics_links['statistics_counter']['title'] = \Drupal::translation()->formatPlural($statistics->getTotalCount(), '1 view', '@count views');
$links['statistics'] = [
'#theme' => 'links__node__statistics',
'#links' => $statistics_links,
'#attributes' => array('class' => array('links', 'inline')),
);
'#attributes' => ['class' => ['links', 'inline']],
];
}
$links['#cache']['max-age'] = \Drupal::config('statistics.settings')->get('display_max_age');
}
@@ -70,18 +71,10 @@ function statistics_node_links_alter(array &$links, NodeInterface $entity, array
* Implements hook_cron().
*/
function statistics_cron() {
$statistics_timestamp = \Drupal::state()->get('statistics.day_timestamp') ?: 0;
if ((REQUEST_TIME - $statistics_timestamp) >= 86400) {
// Reset day counts.
db_update('node_counter')
->fields(array('daycount' => 0))
->execute();
\Drupal::state()->set('statistics.day_timestamp', REQUEST_TIME);
}
// Calculate the maximum of node views, for node search ranking.
\Drupal::state()->set('statistics.node_counter_scale', 1.0 / max(1.0, db_query('SELECT MAX(totalcount) FROM {node_counter}')->fetchField()));
$storage = \Drupal::service('statistics.storage.node');
$storage->resetDayCount();
$max_total_count = $storage->maxTotalCount();
\Drupal::state()->set('statistics.node_counter_scale', 1.0 / max(1.0, $max_total_count));
}
/**
@@ -95,21 +88,21 @@ function statistics_cron() {
* @param int $dbrows
* The number of rows to be returned.
*
* @return SelectQuery|FALSE
* @return SelectQuery|false
* A query result containing the node ID, title, user ID that owns the node,
* and the username for the selected node(s), or FALSE if the query could not
* be executed correctly.
*/
function statistics_title_list($dbfield, $dbrows) {
if (in_array($dbfield, array('totalcount', 'daycount', 'timestamp'))) {
if (in_array($dbfield, ['totalcount', 'daycount', 'timestamp'])) {
$query = db_select('node_field_data', 'n');
$query->addTag('node_access');
$query->join('node_counter', 's', 'n.nid = s.nid');
$query->join('users_field_data', 'u', 'n.uid = u.uid');
return $query
->fields('n', array('nid', 'title'))
->fields('u', array('uid', 'name'))
->fields('n', ['nid', 'title'])
->fields('u', ['uid', 'name'])
->condition($dbfield, 0, '<>')
->condition('n.status', 1)
// @todo This should be actually filtering on the desired node status
@@ -123,26 +116,27 @@ function statistics_title_list($dbfield, $dbrows) {
return FALSE;
}
/**
* Retrieves a node's "view statistics".
*
* @param int $nid
* The node ID.
*
* @return array
* An associative array containing:
* - totalcount: Integer for the total number of times the node has been
* viewed.
* - daycount: Integer for the total number of times the node has been viewed
* "today". For the daycount to be reset, cron must be enabled.
* - timestamp: Integer for the timestamp of when the node was last viewed.
* @deprecated in Drupal 8.2.x, will be removed before Drupal 9.0.0.
* Use \Drupal::service('statistics.storage.node')->fetchView($id).
*/
function statistics_get($nid) {
function statistics_get($id) {
if ($id > 0) {
/** @var \Drupal\statistics\StatisticsViewsResult $statistics */
$statistics = \Drupal::service('statistics.storage.node')->fetchView($id);
if ($nid > 0) {
// Retrieve an array with both totalcount and daycount.
return db_query('SELECT totalcount, daycount, timestamp FROM {node_counter} WHERE nid = :nid', array(':nid' => $nid), array('target' => 'replica'))->fetchAssoc();
// For backwards compatibility, return FALSE if an invalid node ID was
// passed in.
if (!($statistics instanceof StatisticsViewsResult)) {
return FALSE;
}
return [
'totalcount' => $statistics->getTotalCount(),
'daycount' => $statistics->getDayCount(),
'timestamp' => $statistics->getTimestamp(),
];
}
}
@@ -151,9 +145,8 @@ function statistics_get($nid) {
*/
function statistics_node_predelete(EntityInterface $node) {
// Clean up statistics table when node is deleted.
db_delete('node_counter')
->condition('nid', $node->id())
->execute();
$id = $node->id();
return \Drupal::service('statistics.storage.node')->deleteViews($id);
}
/**
@@ -161,15 +154,15 @@ function statistics_node_predelete(EntityInterface $node) {
*/
function statistics_ranking() {
if (\Drupal::config('statistics.settings')->get('count_content_views')) {
return array(
'views' => array(
return [
'views' => [
'title' => t('Number of views'),
'join' => array(
'join' => [
'type' => 'LEFT',
'table' => 'node_counter',
'alias' => 'node_counter',
'on' => 'node_counter.nid = i.sid',
),
],
// Inverse law that maps the highest view count on the site to 1 and 0
// to 0. Note that the ROUND here is necessary for PostgreSQL and SQLite
// in order to ensure that the :statistics_scale argument is treated as
@@ -177,9 +170,9 @@ function statistics_ranking() {
// values in as strings instead of numbers in complex expressions like
// this.
'score' => '2.0 - 2.0 / (1.0 + node_counter.totalcount * (ROUND(:statistics_scale, 4)))',
'arguments' => array(':statistics_scale' => \Drupal::state()->get('statistics.node_counter_scale') ?: 0),
),
);
'arguments' => [':statistics_scale' => \Drupal::state()->get('statistics.node_counter_scale') ?: 0],
],
];
}
}
+4 -11
View File
@@ -14,8 +14,9 @@ $autoloader = require_once 'autoload.php';
$kernel = DrupalKernel::createFromRequest(Request::createFromGlobals(), $autoloader, 'prod');
$kernel->boot();
$container = $kernel->getContainer();
$views = $kernel->getContainer()
$views = $container
->get('config.factory')
->get('statistics.settings')
->get('count_content_views');
@@ -23,15 +24,7 @@ $views = $kernel->getContainer()
if ($views) {
$nid = filter_input(INPUT_POST, 'nid', FILTER_VALIDATE_INT);
if ($nid) {
\Drupal::database()->merge('node_counter')
->key('nid', $nid)
->fields(array(
'daycount' => 1,
'totalcount' => 1,
'timestamp' => REQUEST_TIME,
))
->expression('daycount', 'daycount + 1')
->expression('totalcount', 'totalcount + 1')
->execute();
$container->get('request_stack')->push(Request::createFromGlobals());
$container->get('statistics.storage.node')->recordView($nid);
}
}
@@ -0,0 +1,6 @@
services:
statistics.storage.node:
class: Drupal\statistics\NodeStatisticsDatabaseStorage
arguments: ['@database', '@state', '@request_stack']
tags:
- { name: backend_overridable }
+11 -11
View File
@@ -11,23 +11,23 @@ use Drupal\Core\Render\BubbleableMetadata;
* Implements hook_token_info().
*/
function statistics_token_info() {
$node['total-count'] = array(
$node['total-count'] = [
'name' => t("Number of views"),
'description' => t("The number of visitors who have read the node."),
);
$node['day-count'] = array(
];
$node['day-count'] = [
'name' => t("Views today"),
'description' => t("The number of visitors who have read the node today."),
);
$node['last-view'] = array(
];
$node['last-view'] = [
'name' => t("Last view"),
'description' => t("The date on which a visitor last read the node."),
'type' => 'date',
);
];
return array(
'tokens' => array('node' => $node),
);
return [
'tokens' => ['node' => $node],
];
}
/**
@@ -36,7 +36,7 @@ function statistics_token_info() {
function statistics_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
$token_service = \Drupal::token();
$replacements = array();
$replacements = [];
if ($type == 'node' & !empty($data['node'])) {
$node = $data['node'];
@@ -58,7 +58,7 @@ function statistics_tokens($type, $tokens, array $data, array $options, Bubbleab
if ($created_tokens = $token_service->findWithPrefix($tokens, 'last-view')) {
$statistics = statistics_get($node->id());
$replacements += $token_service->generate('date', $created_tokens, array('date' => $statistics['timestamp']), $options, $bubbleable_metadata);
$replacements += $token_service->generate('date', $created_tokens, ['date' => $statistics['timestamp']], $options, $bubbleable_metadata);
}
}
+34 -34
View File
@@ -11,66 +11,66 @@
function statistics_views_data() {
$data['node_counter']['table']['group'] = t('Content statistics');
$data['node_counter']['table']['join'] = array(
'node_field_data' => array(
$data['node_counter']['table']['join'] = [
'node_field_data' => [
'left_field' => 'nid',
'field' => 'nid',
),
);
],
];
$data['node_counter']['totalcount'] = array(
$data['node_counter']['totalcount'] = [
'title' => t('Total views'),
'help' => t('The total number of times the node has been viewed.'),
'field' => array(
'field' => [
'id' => 'statistics_numeric',
'click sortable' => TRUE,
),
'filter' => array(
],
'filter' => [
'id' => 'numeric',
),
'argument' => array(
],
'argument' => [
'id' => 'numeric',
),
'sort' => array(
],
'sort' => [
'id' => 'standard',
),
);
],
];
$data['node_counter']['daycount'] = array(
$data['node_counter']['daycount'] = [
'title' => t('Views today'),
'help' => t('The total number of times the node has been viewed today.'),
'field' => array(
'field' => [
'id' => 'statistics_numeric',
'click sortable' => TRUE,
),
'filter' => array(
],
'filter' => [
'id' => 'numeric',
),
'argument' => array(
],
'argument' => [
'id' => 'numeric',
),
'sort' => array(
],
'sort' => [
'id' => 'standard',
),
);
],
];
$data['node_counter']['timestamp'] = array(
$data['node_counter']['timestamp'] = [
'title' => t('Most recent view'),
'help' => t('The most recent time the node has been viewed.'),
'field' => array(
'field' => [
'id' => 'node_counter_timestamp',
'click sortable' => TRUE,
),
'filter' => array(
],
'filter' => [
'id' => 'date',
),
'argument' => array(
],
'argument' => [
'id' => 'date',
),
'sort' => array(
],
'sort' => [
'id' => 'standard',
),
);
],
];
return $data;
}
@@ -8,8 +8,8 @@ dependencies:
- statistics
- views
# Information added by Drupal.org packaging script on 2016-08-03
version: '8.1.8'
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
core: '8.x'
project: 'drupal'
datestamp: 1470233790
datestamp: 1502903957
@@ -223,7 +223,7 @@ display:
plugin_id: numeric
filters:
status:
value: true
value: '1'
table: node_field_data
field: status
id: status
@@ -0,0 +1,173 @@
<?php
namespace Drupal\Tests\statistics\Functional;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\Traits\Core\CronRunTrait;
/**
* Tests the statistics admin.
*
* @group statistics
*/
class StatisticsAdminTest extends BrowserTestBase {
use CronRunTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'statistics'];
/**
* A user that has permission to administer statistics.
*
* @var \Drupal\user\UserInterface
*/
protected $privilegedUser;
/**
* A page node for which to check content statistics.
*
* @var \Drupal\node\NodeInterface
*/
protected $testNode;
/**
* The Guzzle HTTP client.
*
* @var \GuzzleHttp\Client;
*/
protected $client;
protected function setUp() {
parent::setUp();
// Set the max age to 0 to simplify testing.
$this->config('statistics.settings')->set('display_max_age', 0)->save();
// Create Basic page node type.
if ($this->profile != 'standard') {
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
}
$this->privilegedUser = $this->drupalCreateUser(['administer statistics', 'view post access counter', 'create page content']);
$this->drupalLogin($this->privilegedUser);
$this->testNode = $this->drupalCreateNode(['type' => 'page', 'uid' => $this->privilegedUser->id()]);
$this->client = \Drupal::httpClient();
}
/**
* Verifies that the statistics settings page works.
*/
public function testStatisticsSettings() {
$config = $this->config('statistics.settings');
$this->assertFalse($config->get('count_content_views'), 'Count content view log is disabled by default.');
// Enable counter on content view.
$edit['statistics_count_content_views'] = 1;
$this->drupalPostForm('admin/config/system/statistics', $edit, t('Save configuration'));
$config = $this->config('statistics.settings');
$this->assertTrue($config->get('count_content_views'), 'Count content view log is enabled.');
// Hit the node.
$this->drupalGet('node/' . $this->testNode->id());
// Manually calling statistics.php, simulating ajax behavior.
$nid = $this->testNode->id();
$post = ['nid' => $nid];
global $base_url;
$stats_path = $base_url . '/' . drupal_get_path('module', 'statistics') . '/statistics.php';
$this->client->post($stats_path, ['form_params' => $post]);
// Hit the node again (the counter is incremented after the hit, so
// "1 view" will actually be shown when the node is hit the second time).
$this->drupalGet('node/' . $this->testNode->id());
$this->client->post($stats_path, ['form_params' => $post]);
$this->assertText('1 view', 'Node is viewed once.');
$this->drupalGet('node/' . $this->testNode->id());
$this->client->post($stats_path, ['form_params' => $post]);
$this->assertText('2 views', 'Node is viewed 2 times.');
// Increase the max age to test that nodes are no longer immediately
// updated, visit the node once more to populate the cache.
$this->config('statistics.settings')->set('display_max_age', 3600)->save();
$this->drupalGet('node/' . $this->testNode->id());
$this->assertText('3 views', 'Node is viewed 3 times.');
$this->client->post($stats_path, ['form_params' => $post]);
$this->drupalGet('node/' . $this->testNode->id());
$this->assertText('3 views', 'Views counter was not updated.');
}
/**
* Tests that when a node is deleted, the node counter is deleted too.
*/
public function testDeleteNode() {
$this->config('statistics.settings')->set('count_content_views', 1)->save();
$this->drupalGet('node/' . $this->testNode->id());
// Manually calling statistics.php, simulating ajax behavior.
$nid = $this->testNode->id();
$post = ['nid' => $nid];
global $base_url;
$stats_path = $base_url . '/' . drupal_get_path('module', 'statistics') . '/statistics.php';
$this->client->post($stats_path, ['form_params' => $post]);
$result = db_select('node_counter', 'n')
->fields('n', ['nid'])
->condition('n.nid', $this->testNode->id())
->execute()
->fetchAssoc();
$this->assertEqual($result['nid'], $this->testNode->id(), 'Verifying that the node counter is incremented.');
$this->testNode->delete();
$result = db_select('node_counter', 'n')
->fields('n', ['nid'])
->condition('n.nid', $this->testNode->id())
->execute()
->fetchAssoc();
$this->assertFalse($result, 'Verifying that the node counter is deleted.');
}
/**
* Tests that cron clears day counts and expired access logs.
*/
public function testExpiredLogs() {
$this->config('statistics.settings')
->set('count_content_views', 1)
->save();
\Drupal::state()->set('statistics.day_timestamp', 8640000);
$this->drupalGet('node/' . $this->testNode->id());
// Manually calling statistics.php, simulating ajax behavior.
$nid = $this->testNode->id();
$post = ['nid' => $nid];
global $base_url;
$stats_path = $base_url . '/' . drupal_get_path('module', 'statistics') . '/statistics.php';
$this->client->post($stats_path, ['form_params' => $post]);
$this->drupalGet('node/' . $this->testNode->id());
$this->client->post($stats_path, ['form_params' => $post]);
$this->assertText('1 view', 'Node is viewed once.');
// statistics_cron() will subtract
// statistics.settings:accesslog.max_lifetime config from REQUEST_TIME in
// the delete query, so wait two secs here to make sure the access log will
// be flushed for the node just hit.
sleep(2);
$this->cronRun();
$this->drupalGet('admin/reports/pages');
$this->assertNoText('node/' . $this->testNode->id(), 'No hit URL found.');
$result = db_select('node_counter', 'nc')
->fields('nc', ['daycount'])
->condition('nid', $this->testNode->id(), '=')
->execute()
->fetchField();
$this->assertFalse($result, 'Daycounter is zero.');
}
}
@@ -0,0 +1,57 @@
<?php
namespace Drupal\Tests\statistics\Functional;
use Drupal\Tests\BrowserTestBase;
use Drupal\node\Entity\Node;
/**
* Tests if statistics.js is loaded when content is not printed.
*
* @group statistics
*/
class StatisticsAttachedTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'statistics'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page']);
// Install "statistics_test_attached" and set it as the default theme.
$theme = 'statistics_test_attached';
\Drupal::service('theme_handler')->install([$theme]);
$this->config('system.theme')
->set('default', $theme)
->save();
// Installing a theme will cause the kernel terminate event to rebuild the
// router. Simulate that here.
\Drupal::service('router.builder')->rebuildIfNeeded();
}
/**
* Tests if statistics.js is loaded when content is not printed.
*/
public function testAttached() {
$node = Node::create([
'type' => 'page',
'title' => 'Page node',
'body' => 'body text'
]);
$node->save();
$this->drupalGet('node/' . $node->id());
$this->assertRaw('core/modules/statistics/statistics.js', 'Statistics library is available');
}
}
@@ -0,0 +1,142 @@
<?php
namespace Drupal\Tests\statistics\Functional;
use Drupal\Tests\BrowserTestBase;
use Drupal\node\Entity\Node;
/**
* Tests request logging for cached and uncached pages.
*
* We subclass WebTestBase rather than StatisticsTestBase, because we
* want to test requests from an anonymous user.
*
* @group statistics
*/
class StatisticsLoggingTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'statistics', 'block', 'locale'];
/**
* User with permissions to create and edit pages.
*
* @var \Drupal\user\UserInterface
*/
protected $authUser;
/**
* Associative array representing a hypothetical Drupal language.
*
* @var array
*/
protected $language;
/**
* The Guzzle HTTP client.
*
* @var \GuzzleHttp\Client;
*/
protected $client;
protected function setUp() {
parent::setUp();
// Create Basic page node type.
if ($this->profile != 'standard') {
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
}
$this->authUser = $this->drupalCreateUser([
// For node creation.
'access content',
'create page content',
'edit own page content',
// For language negotiation administration.
'administer languages',
'access administration pages',
]);
// Ensure we have a node page to access.
$this->node = $this->drupalCreateNode(['title' => $this->randomMachineName(255), 'uid' => $this->authUser->id()]);
// Add a custom language and enable path-based language negotiation.
$this->drupalLogin($this->authUser);
$this->language = [
'predefined_langcode' => 'custom',
'langcode' => 'xx',
'label' => $this->randomMachineName(16),
'direction' => 'ltr',
];
$this->drupalPostForm('admin/config/regional/language/add', $this->language, t('Add custom language'));
$this->drupalPostForm('admin/config/regional/language/detection', ['language_interface[enabled][language-url]' => 1], t('Save settings'));
$this->drupalLogout();
// Enable access logging.
$this->config('statistics.settings')
->set('count_content_views', 1)
->save();
// Clear the logs.
db_truncate('node_counter');
$this->client = \Drupal::httpClient();
}
/**
* Verifies node hit counter logging and script placement.
*/
public function testLogging() {
$path = 'node/' . $this->node->id();
$module_path = drupal_get_path('module', 'statistics');
$stats_path = base_path() . $module_path . '/statistics.php';
$lib_path = base_path() . $module_path . '/statistics.js';
$expected_library = '/<script src=".*?' . preg_quote($lib_path, '/.') . '.*?">/is';
// Verify that logging scripts are not found on a non-node page.
$this->drupalGet('node');
$settings = $this->getDrupalSettings();
$this->assertNoPattern($expected_library, 'Statistics library JS not found on node page.');
$this->assertFalse(isset($settings['statistics']), 'Statistics settings not found on node page.');
// Verify that logging scripts are not found on a non-existent node page.
$this->drupalGet('node/9999');
$settings = $this->getDrupalSettings();
$this->assertNoPattern($expected_library, 'Statistics library JS not found on non-existent node page.');
$this->assertFalse(isset($settings['statistics']), 'Statistics settings not found on node page.');
// Verify that logging scripts are found on a valid node page.
$this->drupalGet($path);
$settings = $this->getDrupalSettings();
$this->assertPattern($expected_library, 'Found statistics library JS on node page.');
$this->assertIdentical($this->node->id(), $settings['statistics']['data']['nid'], 'Found statistics settings on node page.');
// Verify the same when loading the site in a non-default language.
$this->drupalGet($this->language['langcode'] . '/' . $path);
$settings = $this->getDrupalSettings();
$this->assertPattern($expected_library, 'Found statistics library JS on a valid node page in a non-default language.');
$this->assertIdentical($this->node->id(), $settings['statistics']['data']['nid'], 'Found statistics settings on valid node page in a non-default language.');
// Manually call statistics.php to simulate ajax data collection behavior.
global $base_root;
$post = ['nid' => $this->node->id()];
$this->client->post($base_root . $stats_path, ['form_params' => $post]);
$node_counter = statistics_get($this->node->id());
$this->assertIdentical($node_counter['totalcount'], '1');
// Try fetching statistics for an invalid node ID and verify it returns
// FALSE.
$node_id = 1000000;
$node = Node::load($node_id);
$this->assertNull($node);
// This is a test specifically for the deprecated statistics_get() function
// and so should remain unconverted until that function is removed.
$result = statistics_get($node_id);
$this->assertIdentical($result, FALSE);
}
}
@@ -0,0 +1,63 @@
<?php
namespace Drupal\Tests\statistics\Functional;
use Drupal\Core\Cache\Cache;
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
/**
* Tests display of statistics report blocks.
*
* @group statistics
*/
class StatisticsReportsTest extends StatisticsTestBase {
use AssertPageCacheContextsAndTagsTrait;
/**
* Tests the "popular content" block.
*/
public function testPopularContentBlock() {
// Clear the block cache to load the Statistics module's block definitions.
$this->container->get('plugin.manager.block')->clearCachedDefinitions();
// Visit a node to have something show up in the block.
$node = $this->drupalCreateNode(['type' => 'page', 'uid' => $this->blockingUser->id()]);
$this->drupalGet('node/' . $node->id());
// Manually calling statistics.php, simulating ajax behavior.
$nid = $node->id();
$post = http_build_query(['nid' => $nid]);
$headers = ['Content-Type' => 'application/x-www-form-urlencoded'];
global $base_url;
$stats_path = $base_url . '/' . drupal_get_path('module', 'statistics') . '/statistics.php';
$client = \Drupal::httpClient();
$client->post($stats_path, ['headers' => $headers, 'body' => $post]);
// Configure and save the block.
$block = $this->drupalPlaceBlock('statistics_popular_block', [
'label' => 'Popular content',
'top_day_num' => 3,
'top_all_num' => 3,
'top_last_num' => 3,
]);
// Get some page and check if the block is displayed.
$this->drupalGet('user');
$this->assertText('Popular content', 'Found the popular content block.');
$this->assertText("Today's", "Found today's popular content.");
$this->assertText('All time', 'Found the all time popular content.');
$this->assertText('Last viewed', 'Found the last viewed popular content.');
$tags = Cache::mergeTags($node->getCacheTags(), $block->getCacheTags());
$tags = Cache::mergeTags($tags, $this->blockingUser->getCacheTags());
$tags = Cache::mergeTags($tags, ['block_view', 'config:block_list', 'node_list', 'rendered', 'user_view']);
$this->assertCacheTags($tags);
$contexts = Cache::mergeContexts($node->getCacheContexts(), $block->getCacheContexts());
$contexts = Cache::mergeContexts($contexts, ['url.query_args:_wrapper_format']);
$this->assertCacheContexts($contexts);
// Check if the node link is displayed.
$this->assertRaw(\Drupal::l($node->label(), $node->urlInfo('canonical')), 'Found link to visited node.');
}
}
@@ -0,0 +1,51 @@
<?php
namespace Drupal\Tests\statistics\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Defines a base class for testing the Statistics module.
*/
abstract class StatisticsTestBase extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'block', 'ban', 'statistics'];
/**
* User with permissions to ban IP's.
*
* @var \Drupal\user\UserInterface
*/
protected $blockingUser;
protected function setUp() {
parent::setUp();
// Create Basic page node type.
if ($this->profile != 'standard') {
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
}
// Create user.
$this->blockingUser = $this->drupalCreateUser([
'access administration pages',
'access site reports',
'ban IP addresses',
'administer blocks',
'administer statistics',
'administer users',
]);
$this->drupalLogin($this->blockingUser);
// Enable logging.
$this->config('statistics.settings')
->set('count_content_views', 1)
->save();
}
}
@@ -0,0 +1,51 @@
<?php
namespace Drupal\Tests\statistics\Functional;
/**
* Generates text using placeholders for dummy content to check statistics token
* replacement.
*
* @group statistics
*/
class StatisticsTokenReplaceTest extends StatisticsTestBase {
/**
* Creates a node, then tests the statistics tokens generated from it.
*/
public function testStatisticsTokenReplacement() {
$language_interface = \Drupal::languageManager()->getCurrentLanguage();
// Create user and node.
$user = $this->drupalCreateUser(['create page content']);
$this->drupalLogin($user);
$node = $this->drupalCreateNode(['type' => 'page', 'uid' => $user->id()]);
// Hit the node.
$this->drupalGet('node/' . $node->id());
// Manually calling statistics.php, simulating ajax behavior.
$nid = $node->id();
$post = http_build_query(['nid' => $nid]);
$headers = ['Content-Type' => 'application/x-www-form-urlencoded'];
global $base_url;
$stats_path = $base_url . '/' . drupal_get_path('module', 'statistics') . '/statistics.php';
$client = \Drupal::httpClient();
$client->post($stats_path, ['headers' => $headers, 'body' => $post]);
$statistics = statistics_get($node->id());
// Generate and test tokens.
$tests = [];
$tests['[node:total-count]'] = 1;
$tests['[node:day-count]'] = 1;
$tests['[node:last-view]'] = format_date($statistics['timestamp']);
$tests['[node:last-view:short]'] = format_date($statistics['timestamp'], 'short');
// Test to make sure that we generated something for each token.
$this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.');
foreach ($tests as $input => $expected) {
$output = \Drupal::token()->replace($input, ['node' => $node], ['langcode' => $language_interface->getId()]);
$this->assertEqual($output, $expected, format_string('Statistics token %token replaced.', ['%token' => $input]));
}
}
}
@@ -2,7 +2,7 @@
namespace Drupal\Tests\statistics\Kernel\Migrate\d6;
use Drupal\config\Tests\SchemaCheckTestTrait;
use Drupal\Tests\SchemaCheckTestTrait;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
@@ -17,14 +17,14 @@ class MigrateStatisticsConfigsTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
public static $modules = array('statistics');
public static $modules = ['statistics'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('d6_statistics_settings');
$this->executeMigration('statistics_settings');
}
/**
@@ -32,9 +32,7 @@ class MigrateStatisticsConfigsTest extends MigrateDrupal6TestBase {
*/
public function testStatisticsSettings() {
$config = $this->config('statistics.settings');
$this->assertIdentical(FALSE, $config->get('access_log.enabled'));
$this->assertIdentical(259200, $config->get('access_log.max_lifetime'));
$this->assertIdentical(0, $config->get('count_content_views'));
$this->assertSame(1, $config->get('count_content_views'));
$this->assertConfigSchema(\Drupal::service('config.typed'), 'statistics.settings', $config->get());
}
@@ -0,0 +1,39 @@
<?php
namespace Drupal\Tests\statistics\Kernel\Migrate\d7;
use Drupal\Tests\SchemaCheckTestTrait;
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
/**
* Upgrade variables to statistics.settings.yml.
*
* @group migrate_drupal_7
*/
class MigrateStatisticsConfigsTest extends MigrateDrupal7TestBase {
use SchemaCheckTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['statistics'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('statistics_settings');
}
/**
* Tests migration of statistics variables to statistics.settings.yml.
*/
public function testStatisticsSettings() {
$config = $this->config('statistics.settings');
$this->assertIdentical(1, $config->get('count_content_views'));
$this->assertConfigSchema(\Drupal::service('config.typed'), 'statistics.settings', $config->get());
}
}
@@ -4,8 +4,8 @@ description: 'Theme for testing attached library'
# version: VERSION
# core: 8.x
# Information added by Drupal.org packaging script on 2016-08-03
version: '8.1.8'
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
core: '8.x'
project: 'drupal'
datestamp: 1470233790
datestamp: 1502903957