knowledge-8.x-1.x-dev/src/Controller/CompetencyController.php
src/Controller/CompetencyController.php
<?php
namespace Drupal\knowledge\Controller;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Datetime\DateFormatter;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Link;
use Drupal\Core\Render\Renderer;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\Core\Utility\TableSort;
use Drupal\knowledge\KnowledgeCompetencyInterface;
use Drupal\knowledge\KnowledgeCompetencyServiceInterface;
use Drupal\user\UserInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Competency Controller.
*/
class CompetencyController extends ControllerBase implements ContainerInjectionInterface {
/**
* The date formatter.
*
* @var \Drupal\Core\Datetime\DateFormatter
*/
protected $dateFormatter;
/**
* The renderer.
*
* @var \Drupal\Core\Render\Renderer
*/
protected $renderer;
/**
* The competency service.
*
* @var \Drupal\knowledge\KnowledgeCompetencyServiceInterface
*/
protected $competency;
/**
* The entity field manager.
*
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected $entityFieldManager;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('date.formatter'),
$container->get('renderer'),
$container->get('knowledge.competency'),
$container->get('entity_field.manager'),
);
}
/**
* Constructs Competency Controller object.
*
* @param \Drupal\Core\Datetime\DateFormatter $date_formatter
* The date formatter.
* @param \Drupal\Core\Render\Renderer $renderer
* The renderer.
* @param \Drupal\knowledge\KnowledgeCompetencyServiceInterface $competency
* The competency service.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
* The entity field manager.
*/
public function __construct(DateFormatter $date_formatter, Renderer $renderer, KnowledgeCompetencyServiceInterface $competency, EntityFieldManagerInterface $entity_field_manager) {
$this->dateFormatter = $date_formatter;
$this->renderer = $renderer;
$this->competency = $competency;
$this->entityFieldManager = $entity_field_manager;
}
/**
* Displays a Competency revision.
*
* @param int $knowledge_competency_revision
* The Competency revision ID.
*
* @return array
* An array suitable for drupal_render().
*/
public function revisionShow($knowledge_competency_revision) {
/** @var \Drupal\knowledge\KnowledgeCompetencyStorageInterface $competency_storage */
$competency_storage = $this->entityTypeManager()->getStorage('knowledge_competency');
/** @var \Drupal\knowledge\KnowledgeCompetencyInterface $knowledge_competency */
$knowledge_competency = $competency_storage->loadRevision($knowledge_competency_revision);
$view_builder = $this->entityTypeManager()->getViewBuilder('knowledge_competency');
return $view_builder->view($knowledge_competency);
}
/**
* Page title callback for a Competency revision.
*
* @param int $knowledge_competency_revision
* The Competency revision ID.
*
* @return string
* The page title.
*/
public function revisionPageTitle($knowledge_competency_revision) {
/** @var \Drupal\knowledge\KnowledgeCompetencyStorageInterface $competency_storage */
$competency_storage = $this->entityTypeManager()->getStorage('knowledge_competency');
/** @var \Drupal\knowledge\KnowledgeCompetencyInterface $knowledge_competency */
$knowledge_competency = $competency_storage->loadRevision($knowledge_competency_revision);
return $this->t('Revision of %title from %date', [
'%title' => $knowledge_competency->label(),
'%date' => $this->dateFormatter->format($knowledge_competency->getRevisionCreationTime()),
]);
}
/**
* Generates an overview table of older revisions of a Competency.
*
* @param \Drupal\knowledge\KnowledgeCompetencyInterface $knowledge_competency
* A Competency object.
*
* @return array
* An array as expected by drupal_render().
*/
public function revisionOverview(KnowledgeCompetencyInterface $knowledge_competency) {
$account = $this->currentUser();
/** @var \Drupal\knowledge\KnowledgeCompetencyStorageInterface $knowledge_competency_storage */
$knowledge_competency_storage = $this->entityTypeManager()->getStorage('knowledge_competency');
$build['#title'] = $this->t('Revisions for %title', ['%title' => $knowledge_competency->label()]);
$header = [$this->t('Revision'), $this->t('Operations')];
$revert_permission = (($account->hasPermission("revert all competency revisions") || $account->hasPermission('administer knowledge_competency')));
$delete_permission = (($account->hasPermission("delete all competency revisions") || $account->hasPermission('administer knowledge_competency')));
$rows = [];
$vids = $knowledge_competency_storage->revisionIds($knowledge_competency);
$latest_revision = TRUE;
foreach (array_reverse($vids) as $vid) {
/** @var \Drupal\knowledge\KnowledgeCompetencyInterface $revision */
$revision = $knowledge_competency_storage->loadRevision($vid);
$username = [
'#theme' => 'username',
'#account' => $revision->getRevisionUser(),
];
// Use revision link to link to revisions that are not active.
$date = $this->dateFormatter->format($revision->getRevisionCreationTime(), 'short');
if ($vid != $knowledge_competency->getRevisionId()) {
$link = Link::fromTextAndUrl($date, new Url('entity.knowledge_competency.revision', [
'knowledge_competency' => $knowledge_competency->id(),
'knowledge_competency_revision' => $vid,
]))->toString();
}
else {
$link = $knowledge_competency->toLink($date)->toString();
}
$row = [];
$column = [
'data' => [
'#type' => 'inline_template',
'#template' => '{% trans %}{{ date }} by {{ username }}{% endtrans %}{% if message %}<p class="revision-log">{{ message }}</p>{% endif %}',
'#context' => [
'date' => $link,
'username' => $this->renderer->renderInIsolation($username),
'message' => [
'#markup' => $revision->getRevisionLogMessage(),
'#allowed_tags' => Xss::getHtmlTagList(),
],
],
],
];
$row[] = $column;
if ($latest_revision) {
$row[] = [
'data' => [
'#prefix' => '<em>',
'#markup' => $this->t('Current revision'),
'#suffix' => '</em>',
],
];
foreach ($row as &$current) {
$current['class'] = ['revision-current'];
}
$latest_revision = FALSE;
}
else {
$links = [];
if ($revert_permission) {
$links['revert'] = [
'title' => $this->t('Revert'),
'url' => Url::fromRoute('entity.knowledge_competency.revision_revert', [
'knowledge_competency' => $knowledge_competency->id(),
'knowledge_competency_revision' => $vid,
]),
];
}
if ($delete_permission) {
$links['delete'] = [
'title' => $this->t('Delete'),
'url' => Url::fromRoute('entity.knowledge_competency.revision_delete', [
'knowledge_competency' => $knowledge_competency->id(),
'knowledge_competency_revision' => $vid,
]),
];
}
$row[] = [
'data' => [
'#type' => 'operations',
'#links' => $links,
],
];
}
$rows[] = $row;
}
$build['knowledge_competency_revisions_table'] = [
'#theme' => 'table',
'#rows' => $rows,
'#header' => $header,
];
return $build;
}
/**
* Returns the competency the belongs to the user.
*
* @param \Drupal\user\UserInterface $user
* The user to get the competency for.
*/
public function userCompetency(UserInterface $user) {
$user_id = $user->id();
$account = $this->currentUser();
if ($user->get('knowledge_coach')->isEmpty()) {
return [
'#markup' => $this->t('@username does not have a coach.', ['@username' => $user->getDisplayName()]),
];
}
$is_self = $account->id() == $user_id;
$is_learner = $account->id() == $user->get('knowledge_coach')->target_id || $account->id() == 1;
$competency = $this->competency->getUserCompetency($user_id);
if ($account->hasPermission('edit learner knowledge_competency')) {
$form_builder = $this->entityFormBuilder();
return $form_builder->getForm($competency);
}
$view_builder = $this->entityTypeManager()->getViewBuilder('knowledge_competency');
return $view_builder->view($competency);
}
/**
* Checks access for a specific request.
*
* @param \Drupal\Core\Session\AccountInterface $account
* Run access checks for this account (leader).
* @param int $user
* The user the competency belongs to.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
public function accessUserCompetency(AccountInterface $account, UserInterface $user) {
$competency = $this->competency->getUserCompetency($user->id());
if ($competency->access('view', $account)) {
return AccessResult::allowed();
}
if ($competency->access('update', $account)) {
return AccessResult::allowed();
}
return AccessResult::neutral();
}
/**
* Checks access for a specific request.
*
* @param \Drupal\Core\Session\AccountInterface $account
* Run access checks for this account (leader).
* @param \Drupal\user\UserInterface $user
* The user the competency belongs to.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
public function accessCompetencyApproval(AccountInterface $account, UserInterface $user) {
$user_id = $user->id();
$competency = $this->competency->getUserCompetency($user_id);
$is_pending = $competency->isPending();
if (!$is_pending) {
throw new NotFoundHttpException();
}
$account_id = $account->id();
if ($account_id == 1) {
return AccessResult::allowed();
}
$leader_id = $user->knowledge_leader->target_id;
return AccessResult::allowedIf($account_id == $leader_id);
}
/**
* The table report of competencies.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
*/
public function competencySummaryReport(Request $request) {
$role_storage = $this->entityTypeManager()->getStorage('user_role');
$fields_definitions = $this->entityFieldManager
->getFieldDefinitions('knowledge_competency', 'knowledge_competency');
$fields = [];
foreach ($fields_definitions as $field_id => $field_definition) {
if (get_class($field_definition) != 'Drupal\field\Entity\FieldConfig') {
continue;
}
$role = $field_definition->getThirdPartySetting('knowledge', 'competency_role', '_none');
if ($role == '_none') {
continue;
}
$fields[$field_id] = $role;
}
$result = views_get_view_result('knowledge_competency_progress');
if (empty($result)) {
return [];
}
$result = $result[0];
$entity = $result->_entity;
if (!$entity) {
return [];
}
$total = $result->id;
$rows = [];
$order = 0;
$i = 0;
foreach ($fields as $field => $role_id) {
$role = $role_storage->load($role_id);
$competency = $entity->$field->getFieldDefinition()->getLabel();
$key = 'knowledge_competency__' . $field . '_' . $field . '_value';
$key = substr($key, 0, 60);
$value = $result->$key;
$percentage = (int) (100 * ($value / $total));
$i += 1;
$rows[] = [$i, $role->label(), $competency, $percentage];
}
$header = [
'id' => [
'data' => $this->t('Id'),
'field' => 'id',
'class' => [RESPONSIVE_PRIORITY_LOW],
'sort' => 'asc',
],
'role' => [
'data' => $this->t('Role'),
'field' => 'role',
],
'competency' => [
'data' => $this->t('Competency'),
'field' => 'competency',
],
'progress' => [
'data' => $this->t('Percentage'),
'field' => 'progress',
],
];
$sort = TableSort::getSort($header, $request);
$order_by = TableSort::getOrder($header, $request)['sql'];
$desc = ($sort === 'desc');
switch ($order_by) {
case 'id':
$order = 0;
break;
case 'role':
$order = 1;
break;
case 'competency':
$order = 2;
break;
case 'progress':
$order = 3;
break;
}
usort($rows, $this->tableSorter($order, $desc));
$data = [];
$colors = [];
$colors['Paddler'] = 'rgba(54, 162, 235';
$colors['Rider'] = 'rgba(54, 255, 200';
$colors['Pro'] = 'rgba(255, 99, 132';
foreach ($rows as $row) {
$role = $row[1];
$competency = $row[2];
$percent = $row[3];
$data['labels'][] = $competency;
$data['datasets'][0]['data'][] = $percent;
if (!isset($colors[$role])) {
$color_array = $this->getColor($role);
$colors[$role] = 'rgba(' . $color_array[0] . ', ' . $color_array[1] . ', ' . $color_array[2];
}
$data['datasets'][0]['backgroundColor'][] = $colors[$role] . ',.4)';
$data['datasets'][0]['borderColor'][] = $colors[$role] . ',.9)';
}
$hash = 'hash';
$build['graph_paddler'] = [
'#type' => 'container',
'#attributes' => [
'class' => ['competency-report'],
'id' => [$hash],
],
'#attached' => [
'library' => ['knowledge/competency_report'],
'drupalSettings' => [
'competency_report' => [
$hash => $data,
],
],
],
];
$build['table'] = [
'#type' => 'table',
'#header' => $header,
'#weight' => 100,
'#rows' => $rows,
'#attributes' => ['class' => ['competency-table-report']],
];
$build['#attached']['library'][] = 'knowledge/competency_report';
return $build;
}
/**
* Custom data sort.
*
* @param string $key
* The key to sort by.
* @param bool $desc
* Whether to sort in descending order.
*/
private function tableSorter($key, $desc) {
return function ($a, $b) use ($key, $desc) {
$res = strnatcmp($a[$key], $b[$key]);
if ($desc) {
$res = -1 * $res;
}
return $res;
};
}
/**
* Get a color based on a number.
*/
public function getColor($num) {
// Modify 'color' to get a different palette.
$hash = md5('color' . $num);
return [
// R.
hexdec(substr($hash, 0, 2)),
// G.
hexdec(substr($hash, 2, 2)),
// B.
hexdec(substr($hash, 4, 2)),
];
}
}
