knowledge-8.x-1.x-dev/src/Plugin/Block/ArticleStates.php
src/Plugin/Block/ArticleStates.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 "Article States" block.
*
* @Block(
* id = "knowledge_article_state",
* admin_label = @Translation("Article States"),
* category = @Translation("Knowledge")
* )
*/
class ArticleStates 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 renderer.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* Article State 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();
$product = $this->getProduct();
$parameters = [];
if ($product != 0) {
$parameters[':product'] = $product;
}
if ($config['context'] != '_none') {
$parameters[':uid'] = $uid;
}
$contentStateQuery = $this->contentStateQuery();
$states = $this->database->query($contentStateQuery, $parameters)
->fetchAllAssoc('moderation_state', \PDO::FETCH_ASSOC);
sort($states);
if (!$states) {
return [
'#markup' => '<p>' . $this->t('There are no knowledge articles.') . '</p>',
];
}
$data = [
'labels' => [],
'datasets' => [
[
'label' => $this->t('moderation_state'),
'data' => [],
'backgroundColor' => [],
],
],
];
foreach ($states as $state) {
$data['labels'][] = ucwords(str_replace('_', ' ', $state['moderation_state']));
$data['datasets'][0]['data'][] = $state['count'] ?? 0;
$data['datasets'][0]['backgroundColor'][] = 'rgba(' . $this->stateColorSelector($state['moderation_state']) . ' .4)';
$data['datasets'][0]['borderColor'][] =
'rgba(' . $this->stateColorSelector($state['moderation_state']) . ' .9)';
}
$build = [
'#cache' => [
'contexts' => [],
],
'#type' => 'container',
'#attributes' => [
'class' => ['knowledge-article-state'],
'id' => [$hash],
],
'#attached' => [
'library' => ['knowledge/article_state'],
'drupalSettings' => [
'knowledge_article_state' => [
$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'),
],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function blockSubmit($form, FormStateInterface $form_state) {
$context = $form_state->getValue('context');
$hash = sha1(serialize([$context]));
$this->setConfigurationValue('context', $context);
$this->setConfigurationValue('hash', $hash);
}
/**
* Returns the sql query for the count of each moderation state.
*/
protected function contentStateQuery() {
$config = $this->getConfiguration();
$product = $this->getProduct();
$sql =
"
SELECT moderation_state, COUNT(moderation_state) as count
FROM {content_moderation_state_field_data}
INNER JOIN {node_field_data} as nfd
ON content_entity_id = nid
";
if ($product != 0) {
$sql .= "
INNER JOIN {node_revision__field_product_ref} as nrfpr
ON nrfpr.entity_id = nid
INNER JOIN {taxonomy_term_field_data} as ttfd
ON nrfpr.field_product_ref_target_id = tid
";
}
$sql .= "
WHERE nfd.type IN ('q_a', 'how_to', 'solution')
AND content_entity_type_id = 'node'
";
if ($config['context'] != '_none') {
$sql .= "
AND nfd.uid = :uid
";
}
if ($product != 0) {
$sql .= "
AND tid = :product
";
}
$sql .= "GROUP BY moderation_state";
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();
}
/**
* Returns the taxonomy id for the context.
*/
protected function getProduct() {
$currentPath = $this->pathCurrent->getPath();
$pathArray = explode('taxonomy/term/', $currentPath);
if (count($pathArray) > 1) {
$pathArray = explode('/', $pathArray[1]);
$product = (int) $pathArray[0];
if (is_int($product)) {
return $product;
}
}
return 0;
}
/**
* Generates a random RGB color.
*/
protected function stateColorSelector($state) {
$color = '255, 99, 132,';
switch ($state) {
case 'archived':
$color = '255, 99, 132,';
break;
case 'not_validated':
$color = '54, 162, 235,';
break;
case 'validated':
$color = '37, 190, 136,';
break;
case 'work_in_progress':
$color = '93, 37, 190,';
break;
}
return $color;
}
}
