knowledge-8.x-1.x-dev/src/Plugin/Block/KnowledgeActivity.php
src/Plugin/Block/KnowledgeActivity.php
<?php
namespace Drupal\knowledge\Plugin\Block;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Path\CurrentPathStack;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides the "Knowledge Activity" block.
*
* @Block(
* id = "knowledge_activity",
* admin_label = @Translation("Knowledge Activity"),
* category = @Translation("Knowledge")
* )
*/
class KnowledgeActivity extends BlockBase implements ContainerFactoryPluginInterface {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* The time service.
*
* @var \Drupal\Component\Datetime\TimeInterface
*/
protected $time;
/**
* The user storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $userStorage;
/**
* The path current service.
*
* @var \Drupal\Core\Path\CurrentPathStack
*/
protected $pathCurrent;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* The renderer.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* Knowledge Activity constructor.
*
* @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\Database\Connection $database
* The database connection.
* @param \Drupal\Component\Datetime\TimeInterface $time
* The time service.
* @param \Drupal\Core\Entity\EntityStorageInterface $user_storage
* The user storage.
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer service.
* @param \Drupal\Core\Path\CurrentPathStack $path_current
* The path service.
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, Connection $database, TimeInterface $time, EntityStorageInterface $user_storage, RendererInterface $renderer, CurrentPathStack $path_current, AccountInterface $current_user) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->database = $database;
$this->time = $time;
$this->userStorage = $user_storage;
$this->renderer = $renderer;
$this->pathCurrent = $path_current;
$this->currentUser = $current_user;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('database'),
$container->get('datetime.time'),
$container->get('entity_type.manager')->getStorage('user'),
$container->get('renderer'),
$container->get('path.current'),
$container->get('current_user')
);
}
/**
* {@inheritdoc}
*/
public function build() {
$config = $this->getConfiguration();
$hash = $config['hash'];
$uid = $this->getUid();
$request_time = $this->time->getCurrentTime();
$items = $config['items'] ?? 10;
$parameters = [];
switch ($config['frequency']) {
case 'day':
$parameters[':format'] = "'%Y-%m-%d'";
$request_time_sub_month = strtotime('-1 day', $request_time);
$request_time_sub_month_end = strtotime("-$items day", $request_time_sub_month);
$max_age = 28800;
break;
case 'week':
$parameters[':format'] = "'%Y-%V'";
$request_time_sub_month = strtotime('-1 week', $request_time);
$request_time_sub_month = strtotime('last day of this week', $request_time_sub_month);
$request_time_sub_month_end = strtotime("-$items week", $request_time_sub_month);
$max_age = 86400;
break;
case 'month':
default:
$parameters[':format'] = "'%Y-%m'";
$request_time_sub_month = strtotime('-1 month', $request_time);
$request_time_sub_month = strtotime('last day of this month', $request_time_sub_month);
$request_time_sub_month_end = strtotime("-$items month", $request_time_sub_month);
$max_age = 86400 * 2;
break;
}
$parameters[':end_date'] = $request_time_sub_month;
$parameters[':start_date'] = $request_time_sub_month_end;
if ($config['context'] != '_none') {
$parameters[':uid'] = $uid;
}
$linkedContentQuery = $this->contentLinkedQuery();
$results2 = $this->database->query($linkedContentQuery, $parameters)
->fetchAllAssoc('date', \PDO::FETCH_ASSOC);
$createdContentQuery = $this->contentCreatedQuery();
$results1 = $this->database->query($createdContentQuery, $parameters)
->fetchAllAssoc('date', \PDO::FETCH_ASSOC);
$dates = array_merge(array_keys($results1), array_keys($results2));
$dates = array_unique($dates);
sort($dates);
if (!$dates) {
return [
'#markup' => '<p>' . $this->t('There has been no knowledge activity.') . '</p>',
];
}
$data = [
'labels' => [],
'datasets' => [
[
'label' => $this->t('Content created'),
'data' => [],
'backgroundColor' => [],
],
[
'label' => $this->t('Content Linked'),
'data' => [],
'backgroundColor' => [],
],
],
];
foreach ($dates as $date) {
$data['labels'][] = $date;
$data['datasets'][0]['data'][] = $results1[$date]['count'] ?? 0;
$data['datasets'][0]['backgroundColor'][] = 'rgba(54, 162, 235,.4)';
$data['datasets'][0]['borderColor'][] = 'rgba(54, 162, 235,.9)';
$data['datasets'][1]['data'][] = $results2[$date]['count'] ?? 0;
$data['datasets'][1]['backgroundColor'][] = 'rgba(255, 99, 132,.4)';
$data['datasets'][1]['borderColor'][] = 'rgba(255, 99, 132,.9)';
}
$build = [
'#cache' => [
'contexts' => [],
'max-age' => $max_age,
],
'#type' => 'container',
'#attributes' => [
'class' => ['knowledge-activity'],
'id' => [$hash],
],
'#attached' => [
'library' => ['knowledge/activity'],
'drupalSettings' => [
'knowledge_activity' => [
$hash => $data,
],
],
],
];
$this->renderer->addCacheableDependency($build, $config);
return $build;
}
/**
* {@inheritdoc}
*/
public function blockForm($form, FormStateInterface $form_state) {
$form = parent::blockForm($form, $form_state);
$config = $this->getConfiguration();
$form['context'] = [
'#type' => 'select',
'#title' => $this->t('Context'),
'#description' => $this->t('Context the report is presented.'),
'#default_value' => $config['context'] ?? '_none',
'#options' => [
'_none' => $this->t('None'),
'user' => $this->t('User'),
'current_user' => $this->t('Current User'),
],
];
$form['frequency'] = [
'#type' => 'select',
'#title' => $this->t('Frequency'),
'#description' => $this->t('Time period.'),
'#default_value' => $config['frequency'] ?? 'month',
'#options' => [
'day' => $this->t('Daily'),
'week' => $this->t('Weekly'),
'month' => $this->t('Monthly'),
],
];
$form['items'] = [
'#type' => 'number',
'#title' => $this->t('Items'),
'#description' => $this->t('Time period.'),
'#default_value' => $config['items'] ?? 6,
];
return $form;
}
/**
* {@inheritdoc}
*/
public function blockSubmit($form, FormStateInterface $form_state) {
$context = $form_state->getValue('context');
$frequency = $form_state->getValue('frequency');
$items = $form_state->getValue('items');
$hash = sha1(serialize([$context, $frequency, $items]));
$this->setConfigurationValue('context', $context);
$this->setConfigurationValue('frequency', $frequency);
$this->setConfigurationValue('items', $items);
$this->setConfigurationValue('hash', $hash);
}
/**
* Returns the sql query for content created by user.
*/
protected function contentCreatedQuery() {
$config = $this->getConfiguration();
$sql = "
SELECT COUNT(*) as count, DATE_FORMAT(FROM_UNIXTIME(created), :format) as date
FROM {node_revision} AS nr
INNER JOIN {node_field_data} AS nfd
ON nr.nid = nfd.nid
WHERE 1 = 1";
if ($config['context'] != '_none') {
$sql .= "
AND uid = :uid
AND revision_uid = :uid
";
}
$sql .= "
AND created BETWEEN :start_date AND :end_date
AND created = revision_timestamp
GROUP BY DATE_FORMAT(FROM_UNIXTIME(created), :format)
ORDER BY DATE_FORMAT(FROM_UNIXTIME(created), :format)
";
return $sql;
}
/**
* Returns the sql query for content created by user.
*/
protected function contentLinkedQuery() {
$config = $this->getConfiguration();
$sql = "
SELECT COUNT(*) as count, DATE_FORMAT(FROM_UNIXTIME(k.created), :format) as date
FROM {knowledge} as k
INNER JOIN {node_field_data} as nfd on k.entity_id = nid
WHERE type IN ('q_a', 'how_to', 'solution')
AND k.entity_type = 'node'
";
if ($config['context'] != '_none') {
$sql .= "
AND k.uid = :uid
";
}
$sql .= "
AND k.created BETWEEN :start_date AND :end_date
GROUP BY DATE_FORMAT(FROM_UNIXTIME(k.created), :format)
ORDER BY DATE_FORMAT(FROM_UNIXTIME(k.created), :format)
";
return $sql;
}
/**
* Returns the user id for the context.
*/
protected function getUid() {
$currentPath = $this->pathCurrent->getPath();
$pathArray = explode('user/', $currentPath);
if (count($pathArray) > 1) {
$pathArray = explode('/', $pathArray[1]);
$uid = (int) $pathArray[0];
if (is_int($uid)) {
return $uid;
}
}
return $this->currentUser->id();
}
}
