class UserController in Opigno statistics 8
Same name and namespace in other branches
- 3.x src/Controller/UserController.php \Drupal\opigno_statistics\Controller\UserController
Class UserController.
Hierarchy
- class \Drupal\Core\Controller\ControllerBase implements ContainerInjectionInterface uses LoggerChannelTrait, MessengerTrait, LinkGeneratorTrait, RedirectDestinationTrait, UrlGeneratorTrait, StringTranslationTrait
- class \Drupal\opigno_statistics\Controller\UserController uses StatisticsPageTrait
Expanded class hierarchy of UserController
File
- src/
Controller/ UserController.php, line 29
Namespace
Drupal\opigno_statistics\ControllerView source
class UserController extends ControllerBase {
use StatisticsPageTrait;
/**
* Database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* Time.
*
* @var \Drupal\Component\Datetime\Time
*/
protected $time;
/**
* Date formatter.
*
* @var \Drupal\Core\Datetime\DateFormatter
*/
protected $date_formatter;
/**
* UserController constructor.
*/
public function __construct(Connection $database, TimeInterface $time, DateFormatterInterface $date_formatter) {
$this->database = $database;
$this->time = $time;
$this->date_formatter = $date_formatter;
}
/**
* Create.
*/
public static function create(ContainerInterface $container) {
return new static($container
->get('database'), $container
->get('datetime.time'), $container
->get('date.formatter'));
}
/**
* Builds render array for a user info block.
*
* @param \Drupal\user\UserInterface $user
* User.
*
* @return array
* Render array.
*/
public function buildUserInfo(UserInterface $user) {
$user_picture = $user
->get('user_picture')
->getValue();
if (isset($user_picture[0]['target_id'])) {
$user_picture = File::load($user_picture[0]['target_id']);
$user_picture = ImageStyle::load('medium')
->buildUrl($user_picture
->getFileUri());
}
else {
$user_picture = base_path() . drupal_get_path('module', 'opigno_statistics') . '/img/picto-profile-default.svg';
}
$created_timestamp = $user
->getCreatedTime();
$accessed_timestamp = $user
->getLastAccessedTime();
$date_joined = $this->date_formatter
->format($created_timestamp, 'custom', 'Y-m-d');
$last_access = $this->date_formatter
->format($accessed_timestamp, 'custom', 'Y-m-d');
$member_for = $this->date_formatter
->formatTimeDiffSince($created_timestamp);
return [
'#type' => 'container',
'#attributes' => [
'class' => [
'user-info',
],
],
[
'#type' => 'container',
'#attributes' => [
'class' => [
'user-info-photo-wrapper',
],
],
isset($user_picture) ? [
'#type' => 'html_tag',
'#tag' => 'div',
'#attributes' => [
'class' => [
'user-info-photo',
],
'style' => 'background-image: url(' . $user_picture . ')',
],
] : [],
],
[
'#type' => 'container',
'#attributes' => [
'class' => [
'user-info-text-wrapper',
],
],
[
'#type' => 'html_tag',
'#tag' => 'span',
'#attributes' => [
'class' => [
'user-info-icon',
],
],
],
[
'#type' => 'html_tag',
'#tag' => 'p',
'#attributes' => [
'class' => [
'user-info-name',
],
],
'#value' => $user
->getDisplayName(),
],
[
'#type' => 'html_tag',
'#tag' => 'p',
'#attributes' => [
'class' => [
'user-info-email',
],
],
'#value' => $user
->getEmail(),
],
[
'#type' => 'html_tag',
'#tag' => 'p',
'#attributes' => [
'class' => [
'user-info-date-joined',
],
],
'#value' => $this
->t('Date joined @date', [
'@date' => $date_joined,
]),
],
[
'#type' => 'html_tag',
'#tag' => 'p',
'#attributes' => [
'class' => [
'user-info-last-access',
],
],
'#value' => $this
->t('Last access @date', [
'@date' => $last_access,
]),
],
[
'#type' => 'html_tag',
'#tag' => 'p',
'#attributes' => [
'class' => [
'user-info-member-for',
],
],
'#value' => $this
->t('Member for @time', [
'@time' => $member_for,
]),
],
],
];
}
/**
* Builds render array for a user badges block.
*
* @param \Drupal\user\UserInterface $user
* User.
*
* @return array
* Render array.
*/
public function buildBadges(UserInterface $user) {
$output = [];
if (\Drupal::moduleHandler()
->moduleExists('opigno_module')) {
try {
$opigno_module_fields = \Drupal::entityTypeManager()
->getStorage('opigno_module')
->getFieldStorageDefinitions();
} catch (\Exception $e) {
$this
->messenger()
->addMessage($e
->getMessage(), 'error');
return [];
}
if (array_key_exists('badge_active', $opigno_module_fields)) {
$uid = $user
->id();
// Get user modules and courses with active badges.
$modules = OpignoModuleBadges::opignoModuleGetUserActiveBadgesModules($uid);
// Prepare active badges data.
$rows = [];
if ($modules) {
foreach ($modules as $module) {
if (!empty($module->field_media_image_target_id)) {
$fid = $module->field_media_image_target_id;
$file = File::load($fid);
$variables = [
'style_name' => 'thumbnail',
'uri' => $file
->getFileUri(),
];
$image = \Drupal::service('image.factory')
->get($file
->getFileUri());
if ($image
->isValid()) {
$variables['width'] = $image
->getWidth();
$variables['height'] = $image
->getHeight();
}
else {
$variables['width'] = $variables['height'] = NULL;
}
$logo_render_array = [
'#theme' => 'image_style',
'#width' => $variables['width'],
'#height' => $variables['height'],
'#style_name' => $variables['style_name'],
'#uri' => $variables['uri'],
];
$badge_image = render($logo_render_array);
}
else {
$badge_image = '';
}
$badge_description_html = !empty($module->badge_description) ? [
'data' => [
'#markup' => $module->badge_description,
],
] : '';
// Get existing badge count.
$badges = OpignoModuleBadges::opignoModuleGetBadges($uid, $module->gid, $module->typology, $module->entity_id);
if (!empty($module->name) && !empty($module->badge_criteria) && !empty($badges)) {
if ($module->badge_criteria == 'finished' && in_array($module->status, [
'passed',
'failed',
]) || $module->badge_criteria == 'success' && $module->status == 'passed') {
$rows[] = [
'data-id' => $module->entity_id,
'data-typology' => strtolower($module->typology),
'data' => [
$module->training,
$badge_image,
$module->badge_name,
$badge_description_html,
$badges,
],
];
}
}
}
}
if ($rows) {
$output = [
'#type' => 'container',
'#attributes' => [
'class' => [
'badges',
],
],
[
'#type' => 'table',
'#attributes' => [
'class' => [
'statistics-table',
'table-striped',
],
],
'#header' => [
$this
->t('Training'),
'',
$this
->t('Badge'),
$this
->t('Description'),
$this
->t('Earned'),
],
'#rows' => $rows,
],
];
}
}
}
return $output;
}
/**
* Returns max score that user can have in this module & activity.
*
* @param \Drupal\opigno_module\Entity\OpignoModule $module
* Module.
* @param \Drupal\opigno_module\Entity\OpignoActivity $activity
* Activity.
*
* @return int
* Score.
*/
protected function getActivityMaxScore(OpignoModule $module, OpignoActivity $activity) {
$moduleHandler = \Drupal::service('module_handler');
if ($moduleHandler
->moduleExists('opigno_skills_system') && $module
->getSkillsActive()) {
$query = $this->database
->select('opigno_module_relationship', 'omr')
->fields('omr', [
'max_score',
])
->condition('omr.child_id', $activity
->id())
->condition('omr.child_vid', $activity
->getRevisionId())
->condition('omr.activity_status', 1);
$results = $query
->execute()
->fetchAll();
}
else {
$query = $this->database
->select('opigno_module_relationship', 'omr')
->fields('omr', [
'max_score',
])
->condition('omr.parent_id', $module
->id())
->condition('omr.parent_vid', $module
->getRevisionId())
->condition('omr.child_id', $activity
->id())
->condition('omr.child_vid', $activity
->getRevisionId())
->condition('omr.activity_status', 1);
$results = $query
->execute()
->fetchAll();
}
if (empty($results)) {
return 0;
}
$result = reset($results);
return $result->max_score;
}
/**
* Build render array for a user module details.
*
* @param \Drupal\user\UserInterface $user
* User.
* @param \Drupal\group\Entity\GroupInterface $training
* Training.
* @param null|\Drupal\group\Entity\GroupInterface $course
* Course.
* @param \Drupal\opigno_module\Entity\OpignoModule $module
* Module.
*
* @return array
* Render array.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function buildModuleDetails(UserInterface $user, GroupInterface $training, $course, OpignoModule $module) {
// Get user training expiration flag.
$expired = LPStatus::isCertificateExpired($training, $user
->id());
// Get training latest certification timestamp.
$latest_cert_date = LPStatus::getTrainingStartDate($training, $user
->id());
$moduleHandler = \Drupal::service('module_handler');
$parent = isset($course) ? $course : $training;
$step = opigno_learning_path_get_module_step($parent
->id(), $user
->id(), $module, $latest_cert_date);
if ($expired) {
$completed_on = '';
}
else {
$completed_on = $step['completed on'];
$completed_on = $completed_on > 0 ? $this->date_formatter
->format($completed_on, 'custom', 'F d, Y') : '';
}
/** @var \Drupal\opigno_module\Entity\OpignoModule $module */
$module = OpignoModule::load($step['id']);
/** @var \Drupal\opigno_module\Entity\UserModuleStatus[] $attempts */
$attempts = !$expired ? $module
->getModuleAttempts($user, NULL, $latest_cert_date) : [];
if ($moduleHandler
->moduleExists('opigno_skills_system') && $module
->getSkillsActive() && $module
->getModuleSkillsGlobal() && !empty($attempts)) {
$activities_from_module = $module
->getModuleActivities();
$activity_ids = array_keys($activities_from_module);
$attempt = $this
->getTargetAttempt($attempts, $module);
$db_connection = \Drupal::service('database');
$query = $db_connection
->select('opigno_answer_field_data', 'o_a_f_d');
$query
->leftJoin('opigno_module_relationship', 'o_m_r', 'o_a_f_d.activity = o_m_r.child_id');
$query
->addExpression('MAX(o_a_f_d.activity)', 'id');
$query
->condition('o_a_f_d.user_id', $user
->id())
->condition('o_a_f_d.module', $module
->id());
if (!$module
->getModuleSkillsGlobal()) {
$query
->condition('o_a_f_d.activity', $activity_ids, 'IN');
}
$query
->condition('o_a_f_d.user_module_status', $attempt
->id())
->groupBy('o_a_f_d.activity');
$activities = $query
->execute()
->fetchAllAssoc('id');
}
else {
$activities = $module
->getModuleActivities();
}
/** @var \Drupal\opigno_module\Entity\OpignoActivity[] $activities */
$activities = array_map(function ($activity) {
/** @var \Drupal\opigno_module\Entity\OpignoActivity $activity */
return OpignoActivity::load($activity->id);
}, $activities);
if (!empty($attempts)) {
// If "newest" score - get the last attempt,
// else - get the best attempt.
$attempt = $this
->getTargetAttempt($attempts, $module);
$max_score = $attempt
->calculateMaxScore();
$score_percent = $attempt
->getAttemptScore();
$score = round($score_percent * $max_score / 100);
}
else {
$attempt = NULL;
$max_score = !empty($activities) ? array_sum(array_map(function ($activity) use ($module) {
return (int) $this
->getActivityMaxScore($module, $activity);
}, $activities)) : 0;
$score_percent = 0;
$score = 0;
}
$activities = array_map(function ($activity) use ($user, $module, $attempt) {
/** @var \Drupal\opigno_module\Entity\OpignoActivity $activity */
/** @var \Drupal\opigno_module\Entity\OpignoAnswer $answer */
$answer = isset($attempt) ? $activity
->getUserAnswer($module, $attempt, $user) : NULL;
$score = isset($answer) ? $answer
->getScore() : 0;
$max_score = (int) $this
->getActivityMaxScore($module, $activity);
if ($max_score == 0 && $activity
->get('auto_skills')
->getValue()[0]['value'] == 1) {
$max_score = 10;
}
if ($answer && $activity
->hasField('opigno_evaluation_method') && $activity
->get('opigno_evaluation_method')->value && !$answer
->isEvaluated()) {
$state_class = 'step_state_pending';
}
else {
$state_class = isset($answer) ? 'step_state_passed' : ($max_score == 0 ? 'step_state_pending' : 'step_state_failed');
}
return [
[
'data' => $activity
->getName(),
],
[
'data' => [
'#markup' => $score . '/' . $max_score,
],
],
[
'data' => [
'#type' => 'html_tag',
'#tag' => 'span',
'#attributes' => [
'class' => [
$state_class,
],
],
'#value' => '',
],
],
];
}, $activities);
$activities = [
'#type' => 'table',
'#attributes' => [
'class' => [
'module_panel_activities_overview',
],
],
'#rows' => $activities,
];
$training_id = $training
->id();
$module_id = $module
->id();
$user_id = $user
->id();
if (isset($course)) {
$course_id = $course
->id();
$id = "module_panel_{$user_id}_{$training_id}_{$course_id}_{$module_id}";
}
else {
$id = "module_panel_{$user_id}_{$training_id}_{$module_id}";
}
if (isset($attempt)) {
$details = Link::createFromRoute($this
->t('Details'), 'opigno_module.module_result', [
'opigno_module' => $module
->id(),
'user_module_status' => $attempt
->id(),
], [
'query' => [
'skip-links' => TRUE,
],
])
->toRenderable();
$details['#attributes']['target'] = '_blank';
}
else {
$details = [];
}
return [
'#type' => 'container',
'#attributes' => [
'id' => $id,
'class' => [
'module_panel',
],
],
[
'#type' => 'container',
'#attributes' => [
'class' => [
'module_panel_header',
],
],
[
'#markup' => '<a href="#" class="module_panel_close">×</a>',
],
[
'#type' => 'html_tag',
'#tag' => 'h3',
'#attributes' => [
'class' => [
'module_panel_title',
],
],
'#value' => $step['name'] . ' ' . (!empty($completed_on) ? t('completed') : ''),
],
],
[
'#type' => 'html_tag',
'#tag' => 'hr',
'#value' => '',
],
[
'#type' => 'container',
'#attributes' => [
'class' => [
'module_panel_content',
],
],
!empty($completed_on) ? [
'#type' => 'html_tag',
'#tag' => 'p',
'#value' => t('@name completed on @date', [
'@name' => $step['name'],
'@date' => $completed_on,
]),
] : [],
!($max_score == 0) ? [
'#type' => 'html_tag',
'#tag' => 'p',
'#value' => t('User got @score of @max_score possible points.', [
'@score' => $score,
'@max_score' => $max_score,
]),
] : [],
!($max_score == 0) ? [
'#type' => 'html_tag',
'#tag' => 'p',
'#value' => t('Total score @percent%', [
'@percent' => $score_percent,
]),
] : [],
[
'#type' => 'html_tag',
'#tag' => 'h3',
'#attributes' => [
'class' => [
'module_panel_overview_title',
],
],
'#value' => t('Activities Overview'),
],
$activities,
$details,
],
];
}
/**
* Get last or best user attempt for Module.
*
* @param array $attempts
* User module attempts.
* @param \Drupal\opigno_module\Entity\OpignoModule $module
* Module.
*
* @return \Drupal\opigno_module\Entity\UserModuleStatus
* $attempt
*/
protected function getTargetAttempt(array $attempts, OpignoModule $module) {
if ($module
->getKeepResultsOption() == 'newest') {
$attempt = end($attempts);
}
else {
$attempt = opigno_learning_path_best_attempt($attempts);
}
return $attempt;
}
/**
* Builds render array for a user course details.
*
* @param \Drupal\user\UserInterface $user
* User.
* @param \Drupal\group\Entity\GroupInterface $training
* Training.
* @param \Drupal\group\Entity\GroupInterface $course
* Course.
*
* @return array
* Render array.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function buildCourseDetails(UserInterface $user, GroupInterface $training, GroupInterface $course) {
// Load group steps.
$steps = opigno_learning_path_get_steps($course
->id(), $user
->id());
$query = $this->database
->select('opigno_learning_path_step_achievements', 'sa');
$query
->leftJoin('opigno_learning_path_step_achievements', 'sa2', 'sa2.parent_id = sa.id');
$query = $query
->fields('sa2', [
'entity_id',
'typology',
'name',
'score',
'status',
])
->condition('sa.uid', $user
->id())
->condition('sa.gid', $training
->id())
->condition('sa.entity_id', $course
->id())
->condition('sa.parent_id', 0);
$modules = $query
->execute()
->fetchAll();
$rows = array_map(function ($step) use ($modules, $training, $course, $user) {
$module = NULL;
foreach ($modules as $mod) {
if ($mod->entity_id === $step['id']) {
$module = $mod;
break;
}
}
$id = isset($module) ? $module->entity_id : $step['id'];
$name = isset($module) ? $module->name : $step['name'];
$score = isset($module) ? $module->score : 0;
$status = isset($module) ? $module->status : 'pending';
$typology = strtolower(isset($module) ? $module->typology : $step['typology']);
$score = isset($score) ? $score : 0;
$score = [
'data' => $this
->buildScore($score),
];
$status = isset($status) ? $status : 'pending';
$status = [
'data' => $this
->buildStatus($status),
];
switch ($typology) {
case 'module':
$training_gid = $training
->id();
$course_gid = $course
->id();
$module_id = $id;
$user_id = $user
->id();
$details = Link::createFromRoute('', 'opigno_statistics.user.course_module_details', [
'user' => $user
->id(),
'training' => $training
->id(),
'course' => $course
->id(),
'module' => $id,
])
->toRenderable();
$details['#attributes']['class'][] = 'details';
$details['#attributes']['class'][] = 'course-module-details-open';
$details['#attributes']['data-user'] = $user_id;
$details['#attributes']['data-training'] = $training_gid;
$details['#attributes']['data-course'] = $course_gid;
$details['#attributes']['data-id'] = $module_id;
$details = [
'data' => [
$details,
[
'#type' => 'container',
'#attributes' => [
'class' => [
'module-panel-wrapper',
],
],
[
'#type' => 'html_tag',
'#tag' => 'span',
'#attributes' => [
'id' => "module_panel_{$user_id}_{$training_gid}_{$course_gid}_{$module_id}",
],
],
],
],
];
break;
default:
$details = '';
break;
}
return [
$name,
$score,
$status,
$details,
];
}, $steps);
return [
'#type' => 'container',
'#attributes' => [
'class' => [
'course-modules',
],
],
[
'#type' => 'table',
'#attributes' => [
'class' => [
'statistics-table',
'course-modules-list',
],
],
'#header' => [],
'#rows' => $rows,
],
];
}
/**
* Builds render array for a user training details.
*
* @param \Drupal\user\UserInterface $user
* User.
* @param \Drupal\group\Entity\GroupInterface $group
* Training.
*
* @return array
* Render array.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function buildTrainingDetails(UserInterface $user, GroupInterface $group) {
$gid = $group
->id();
$uid = $user
->id();
// Get user training expiration flag.
$expired = LPStatus::isCertificateExpired($group, $uid);
// Get training latest certification timestamp.
$latest_cert_date = LPStatus::getTrainingStartDate($group, $uid);
// Load group steps.
// Get training guided navigation option.
$freeNavigation = !OpignoGroupManagerController::getGuidedNavigation($group);
if ($freeNavigation) {
// Get all steps for LP.
$steps = opigno_learning_path_get_all_steps($gid, $uid, NULL, $latest_cert_date);
}
else {
// Get guided steps.
$steps = opigno_learning_path_get_steps($gid, $uid, NULL, $latest_cert_date);
}
$steps_count = count($steps);
if ($expired) {
$passed_modules_count = 0;
$training_data = [
'progress' => 0,
'score' => 0,
'time' => 0,
];
$modules = [];
}
else {
$query = $this->database
->select('opigno_learning_path_achievements', 'a')
->fields('a', [
'score',
'progress',
'time',
'completed',
])
->condition('a.gid', $gid)
->condition('a.uid', $uid);
$training_data = $query
->execute()
->fetchAssoc();
$query = $this->database
->select('opigno_learning_path_step_achievements', 'sa')
->fields('sa', [
'entity_id',
'typology',
'name',
'score',
'status',
'time',
'completed',
])
->condition('sa.gid', $gid)
->condition('sa.uid', $uid)
->condition('sa.parent_id', 0);
$modules = $query
->execute()
->fetchAll();
$passed_modules = array_filter($modules, function ($module) {
return $module->status === 'passed';
});
$passed_modules_count = count($passed_modules);
}
$content = [
'#type' => 'container',
'#attributes' => [
'class' => [
'training-details-content',
],
],
];
$content[] = [
'#type' => 'container',
'#attributes' => [
'class' => [
'module-passed',
],
],
'module_passed' => $this
->buildValueWithIndicator($this
->t('Module Passed'), $passed_modules_count / $steps_count, $this
->t('@passed/@total', [
'@passed' => $passed_modules_count,
'@total' => $steps_count,
])),
];
$content[] = [
'#type' => 'container',
'#attributes' => [
'class' => [
'completion',
],
],
'completion' => $this
->buildValueWithIndicator($this
->t('Completion'), $training_data['progress'] / 100),
];
$content[] = [
'#type' => 'container',
'#attributes' => [
'class' => [
'score',
],
],
'completion' => $this
->buildValueWithIndicator($this
->t('Score'), $training_data['score'] / 100),
];
$time = isset($training_data['time']) && $training_data['time'] > 0 ? $this->date_formatter
->formatInterval($training_data['time']) : '-';
if (isset($training_data['completed'])) {
$datetime = DrupalDateTime::createFromFormat(DrupalDateTime::FORMAT, $training_data['completed']);
$timestamp = $datetime
->getTimestamp();
$completed_on = $this->date_formatter
->format($timestamp, 'custom', 'F d Y');
}
else {
$completed_on = '-';
}
$content[] = [
'#type' => 'container',
'#attributes' => [
'class' => [
'right-block',
],
],
[
'#type' => 'container',
'#attributes' => [
'class' => [
'time',
],
],
[
'#type' => 'container',
'#attributes' => [
'class' => [
'value-wrapper',
],
],
[
'#type' => 'html_tag',
'#tag' => 'span',
'#attributes' => [
'class' => [
'label',
],
],
'#value' => $this
->t('Time spent'),
],
[
'#type' => 'html_tag',
'#tag' => 'span',
'#attributes' => [
'class' => [
'value',
],
],
'#value' => $time,
],
],
],
[
'#type' => 'container',
'#attributes' => [
'class' => [
'completed',
],
],
[
'#type' => 'container',
'#attributes' => [
'class' => [
'value-wrapper',
],
],
[
'#type' => 'html_tag',
'#tag' => 'span',
'#attributes' => [
'class' => [
'label',
],
],
'#value' => $this
->t('Completed on'),
],
[
'#type' => 'html_tag',
'#tag' => 'span',
'#attributes' => [
'class' => [
'value',
],
],
'#value' => $completed_on,
],
],
],
];
$rows = array_map(function ($step) use ($modules, $uid, $gid) {
$module = NULL;
foreach ($modules as $mod) {
if ($mod->entity_id == $step['id'] && $mod->typology == $step["typology"]) {
$module = $mod;
break;
}
}
$id = isset($module) ? $module->entity_id : $step['id'];
$name = isset($module) ? $module->name : $step['name'];
$score = $step['current attempt score'];
$status = isset($module) ? $module->status : 'pending';
$typology = strtolower(isset($module) ? $module->typology : $step['typology']);
$score = isset($score) ? $score : 0;
$score = [
'data' => $this
->buildScore($score),
];
$status = isset($status) ? $status : 'pending';
$status = [
'data' => $this
->buildStatus($status),
];
switch ($typology) {
case 'course':
$details = Link::createFromRoute('', 'opigno_statistics.user.course_details', [
'user' => $uid,
'training' => $gid,
'course' => $id,
])
->toRenderable();
$details['#attributes']['class'][] = 'details';
$details['#attributes']['class'][] = 'course-details-open';
$details['#attributes']['data-user'] = $uid;
$details['#attributes']['data-training'] = $gid;
$details['#attributes']['data-id'] = $id;
$details = [
'data' => $details,
];
break;
case 'module':
$module_id = $id;
$details = Link::createFromRoute('', 'opigno_statistics.user.training_module_details', [
'user' => $uid,
'training' => $gid,
'module' => $module_id,
])
->toRenderable();
$details['#attributes']['class'][] = 'details';
$details['#attributes']['class'][] = 'training-module-details-open';
$details['#attributes']['data-user'] = $uid;
$details['#attributes']['data-training'] = $gid;
$details['#attributes']['data-id'] = $module_id;
$details = [
'data' => [
$details,
[
'#type' => 'container',
'#attributes' => [
'class' => [
'module-panel-wrapper',
],
],
[
'#type' => 'html_tag',
'#tag' => 'span',
'#attributes' => [
'id' => "module_panel_{$uid}_{$gid}_{$module_id}",
],
],
],
],
];
break;
default:
$details = '';
break;
}
$is_course = $typology === 'course';
return [
'class' => $is_course ? 'course' : 'module',
'data-training' => $gid,
'data-id' => $id,
'data-user' => $uid,
'data' => [
$name,
$score,
$status,
$details,
],
];
}, $steps);
$content[] = [
'#type' => 'html_tag',
'#tag' => 'hr',
];
$current_route = \Drupal::routeMatch()
->getRouteName();
$content[] = [
'#type' => 'container',
'#attributes' => [
'class' => [
'training-modules',
],
],
[
'#type' => 'table',
'#attributes' => [
'class' => [
!empty($current_route) && $current_route == 'opigno_statistics.user.training_details' ? 'trainings-list' : '',
'statistics-table',
'training-modules-list',
'mb-0',
],
],
'#header' => [
$this
->t('Course / Module'),
$this
->t('Results'),
$this
->t('State'),
'',
],
'#rows' => $rows,
],
];
return $content;
}
/**
* Loads module panel with a AJAX.
*
* @param \Drupal\user\UserInterface $user
* User.
* @param \Drupal\group\Entity\GroupInterface $training
* Training.
* @param null|\Drupal\group\Entity\GroupInterface $course
* Course.
* @param \Drupal\opigno_module\Entity\OpignoModule $module
* Module.
*
* @return \Drupal\Core\Ajax\AjaxResponse
* AJAX response.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function ajaxLoadCourseModuleDetails(UserInterface $user, GroupInterface $training, GroupInterface $course, OpignoModule $module) {
$training_id = $training
->id();
$course_id = $course
->id();
$module_id = $module
->id();
$user_id = $user
->id();
$selector = "#module_panel_{$user_id}_{$training_id}_{$course_id}_{$module_id}";
$content = $this
->buildModuleDetails($user, $training, $course, $module);
$content['#attributes']['data-ajax-loaded'] = TRUE;
$response = new AjaxResponse();
$response
->addCommand(new ReplaceCommand($selector, $content));
return $response;
}
/**
* Loads module panel with a AJAX.
*
* @param \Drupal\user\UserInterface $user
* User.
* @param \Drupal\group\Entity\GroupInterface $training
* Training.
* @param \Drupal\opigno_module\Entity\OpignoModule $module
* Module.
*
* @return \Drupal\Core\Ajax\AjaxResponse
* AJAX response.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function ajaxLoadTrainingModuleDetails(UserInterface $user, GroupInterface $training, OpignoModule $module) {
$training_id = $training
->id();
$module_id = $module
->id();
$user_id = $user
->id();
$selector = "#module_panel_{$user_id}_{$training_id}_{$module_id}";
$content = $this
->buildModuleDetails($user, $training, NULL, $module);
$content['#attributes']['data-ajax-loaded'] = TRUE;
$response = new AjaxResponse();
$response
->addCommand(new ReplaceCommand($selector, $content));
return $response;
}
/**
* Loads a user course details with the AJAX.
*
* @param \Drupal\user\UserInterface $user
* User.
* @param \Drupal\group\Entity\GroupInterface $training
* Training.
* @param \Drupal\group\Entity\GroupInterface $course
* Course.
*
* @return \Drupal\Core\Ajax\AjaxResponse
* AJAX response.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function ajaxLoadCourseDetails(UserInterface $user, GroupInterface $training, GroupInterface $course) {
$training_gid = $training
->id();
$course_gid = $course
->id();
$user_id = $user
->id();
$selector = ".training-modules-list tr.course[data-user=\"{$user_id}\"][data-training=\"{$training_gid}\"][data-id=\"{$course_gid}\"]";
$content = [
[
'#type' => 'html_tag',
'#tag' => 'tr',
'#attributes' => [
'data-training' => $training_gid,
'data-id' => $course_gid,
'class' => [
'course-active',
],
],
[
'#type' => 'html_tag',
'#tag' => 'td',
'#attributes' => [
'colspan' => 3,
],
'#value' => $course
->label(),
],
[
'#type' => 'html_tag',
'#tag' => 'td',
'close' => [
'#type' => 'html_tag',
'#tag' => 'span',
'#attributes' => [
'data-training' => $training_gid,
'data-id' => $course_gid,
'class' => [
'course-close',
],
],
],
],
],
[
'#type' => 'html_tag',
'#tag' => 'tr',
'#attributes' => [
'data-training' => $training_gid,
'data-id' => $course_gid,
'class' => [
'course-details',
],
],
[
'#type' => 'html_tag',
'#tag' => 'td',
'#attributes' => [
'colspan' => 4,
],
'details' => $this
->buildCourseDetails($user, $training, $course),
],
],
];
$content['#attached']['library'][] = 'opigno_statistics/user';
$response = new AjaxResponse();
$response
->addCommand(new AfterCommand($selector, $content));
return $response;
}
/**
* Loads a user training details with the AJAX.
*
* @param \Drupal\user\UserInterface $user
* User.
* @param \Drupal\group\Entity\GroupInterface $group
* Training.
*
* @return \Drupal\Core\Ajax\AjaxResponse
* AJAX response.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function ajaxLoadTrainingDetails(UserInterface $user, GroupInterface $group) {
$gid = $group
->id();
$uid = $user
->id();
$selector = ".trainings-list tr.training[data-training=\"{$gid}\"][data-user=\"{$uid}\"]";
$content = [
[
'#type' => 'html_tag',
'#tag' => 'tr',
'#attributes' => [
'data-training' => $gid,
'data-user' => $uid,
'class' => [
'training-active',
],
],
[
'#type' => 'html_tag',
'#tag' => 'td',
'#attributes' => [
'colspan' => 4,
],
'#value' => $group
->label(),
],
[
'#type' => 'html_tag',
'#tag' => 'td',
'close' => [
'#type' => 'html_tag',
'#tag' => 'span',
'#attributes' => [
'data-training' => $gid,
'data-user' => $uid,
'class' => [
'training-close',
],
],
],
],
],
[
'#type' => 'html_tag',
'#tag' => 'tr',
'#attributes' => [
'data-training' => $gid,
'data-user' => $uid,
'class' => [
'training-details',
],
],
[
'#type' => 'html_tag',
'#tag' => 'td',
'#attributes' => [
'colspan' => 5,
],
'details' => $this
->buildTrainingDetails($user, $group),
],
],
];
$content['#attached']['library'][] = 'opigno_statistics/user';
$response = new AjaxResponse();
$response
->addCommand(new AfterCommand($selector, $content));
return $response;
}
/**
* Builds render array for a user trainings list.
*
* @param \Drupal\user\UserInterface $user
* User.
*
* @return array
* Render array.
*/
public function buildTrainingsList(UserInterface $user) {
$query = $this->database
->select('opigno_learning_path_achievements', 'a')
->fields('a', [
'gid',
'name',
'score',
'status',
'time',
])
->condition('a.uid', $user
->id())
->groupBy('a.gid')
->groupBy('a.name')
->groupBy('a.score')
->groupBy('a.status')
->groupBy('a.time')
->orderBy('a.name');
$rows = $query
->execute()
->fetchAll();
$rows = array_map(function ($row) use ($user) {
$uid = $user
->id();
$gid = $row->gid;
$name = $row->name;
$score = isset($row->score) ? $row->score : 0;
$score = [
'data' => $this
->buildScore($score),
];
$status = isset($row->status) ? $row->status : 'pending';
$status = [
'data' => $this
->buildStatus($status),
];
$time_spent = $row->time > 0 ? $this->date_formatter
->formatInterval($row->time) : '-';
$details = Link::createFromRoute('', 'opigno_statistics.user.training_details', [
'user' => $uid,
'group' => $gid,
])
->toRenderable();
$details['#attributes']['class'][] = 'details';
$details['#attributes']['data-user'] = $uid;
$details['#attributes']['data-training'] = $gid;
$details = [
'data' => $details,
];
return [
'class' => 'training',
'data-training' => $gid,
'data-user' => $uid,
'data' => [
$name,
$score,
$status,
$time_spent,
$details,
],
];
}, $rows);
return [
'#type' => 'container',
'#attributes' => [
'class' => [
'trainings-list',
],
],
[
'#type' => 'table',
'#attributes' => [
'class' => [
'statistics-table',
'trainings-list',
'table-striped',
],
],
'#header' => [
$this
->t('Training'),
$this
->t('Score'),
$this
->t('Passed'),
$this
->t('Time spent'),
$this
->t('Details'),
],
'#rows' => $rows,
],
];
}
/**
* Builds render array for a user skills list.
*
* @param \Drupal\user\UserInterface $user
* User.
*
* @return array
* Render array.
*/
public function buildSkillsList(UserInterface $user) {
$content = [];
$parent_terms = [];
$parent_tids = [];
$term_storage = \Drupal::entityTypeManager()
->getStorage('taxonomy_term');
$query = $this->database
->select('opigno_skills_statistic', 'a')
->fields('a', [
'tid',
'score',
'progress',
'stage',
])
->condition('a.uid', $user
->id());
$user_skills = $query
->execute()
->fetchAllAssoc('tid');
foreach ($user_skills as $skill) {
if ($term_storage
->load($skill->tid)) {
$parents = $term_storage
->loadAllParents($skill->tid);
$parent = array_pop($parents);
$parent_tids[$parent
->id()] = FALSE;
if (empty($parent_terms[$parent
->id()])) {
$tree = $term_storage
->loadTree('skills', $parent
->id());
$depth = [];
foreach ($tree as $skill_entity) {
if (!isset($depth[$skill_entity->depth])) {
$depth[$skill_entity->depth] = 0;
}
$depth[$skill_entity->depth]++;
}
$content[$parent
->id()]['width'] = max($depth);
$tree_parent = new \stdClass();
$tree_parent->tid = $parent
->id();
$tree_parent->name = $parent
->getName();
$tree_parent->parents[0] = 'empty';
$tree[] = $tree_parent;
$parent_terms[$parent
->id()] = $tree;
}
}
}
foreach ($parent_terms as $id => $skills) {
foreach ($skills as $skill) {
$content[$id]['skills'][$skill->tid] = [
'id' => $skill->tid,
'label' => $skill->name,
'group' => $this
->t('pending'),
];
$content[$id]['arrows'][$skill->tid] = [
'from' => $skill->tid,
'to' => $skill->parents[0],
];
if (empty($user_skills[$skill->tid])) {
unset($parent_tids[$skill->parents[0]]);
continue;
}
if ($user_skills[$skill->tid]->stage == 0) {
$content[$id]['skills'][$skill->tid]['group'] = $this
->t('done');
if (isset($parent_tids[$skill->parents[0]])) {
$parent_tids[$skill->parents[0]] = $id;
}
}
else {
unset($parent_tids[$skill->parents[0]]);
}
$content[$id]['skills'][$skill->tid]['title'] = $this
->t('Score:') . ' ' . $user_skills[$skill->tid]->score;
$content[$id]['arrows'][$skill->tid]['label'] = $user_skills[$skill->tid]->progress . '%';
}
}
$parent_tids = array_filter($parent_tids);
foreach ($parent_tids as $id => $item) {
$content[$item]['skills'][$id]['group'] = $this
->t('done');
}
return $content;
}
/**
* Builds render array for a user skills table.
*
* @param \Drupal\user\UserInterface $user
* User.
*
* @return array
* Render array.
*/
public function buildSkillsTable(UserInterface $user, $tree = FALSE) {
$query = $this->database
->select('opigno_skills_statistic', 'a')
->fields('a', [
'tid',
'score',
'progress',
'stage',
])
->condition('a.uid', $user
->id());
if ($tree) {
$query
->condition('a.tid', $tree, 'IN');
}
$rows = $query
->execute()
->fetchAll();
$rows = array_map(function ($row) use ($user) {
$score = [
'data' => $this
->buildScore($row->score),
];
$progress = [
'data' => $this
->buildScore($row->progress),
];
$term = \Drupal::entityTypeManager()
->getStorage('taxonomy_term')
->load($row->tid);
$skill_name = $term
->getName();
$level = 'N/A';
$levels = $term
->get('field_level_names');
if (!empty($levels)) {
$levels = $levels
->getValue();
$count_of_levels = count($levels);
}
if (!empty($levels) && $count_of_levels != $row->stage) {
$level = $levels[$row->stage]['value'];
}
return [
'class' => 'training',
'data-training' => $row->tid,
'data' => [
$skill_name,
$score,
$progress,
$level,
],
];
}, $rows);
$rows = array_filter($rows);
if ($rows) {
return [
'#type' => 'container',
'#attributes' => [
'class' => [
'skills-list',
],
],
[
'#type' => 'table',
'#attributes' => [
'class' => [
'statistics-table',
'skills-list',
'table-striped',
],
],
'#header' => [
$this
->t('Skill'),
$this
->t('Score'),
$this
->t('Progress'),
$this
->t('Level'),
],
'#rows' => $rows,
],
];
}
else {
return [];
}
}
/**
* Builds render array for a user course statistics page.
*
* @param \Drupal\user\UserInterface $user
* User.
* @param \Drupal\group\Entity\GroupInterface $training
* Training.
* @param \Drupal\group\Entity\GroupInterface $course
* Course.
* @param \Drupal\opigno_module\Entity\OpignoModule $module
* Module.
*
* @return array
* Render array.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function courseModule(UserInterface $user, GroupInterface $training, GroupInterface $course, OpignoModule $module) {
$content = [];
$content[] = $this
->buildModuleDetails($user, $training, $course, $module);
$content['#attached']['library'][] = 'opigno_statistics/user';
return $content;
}
/**
* Builds render array for a user course statistics page.
*
* @param \Drupal\user\UserInterface $user
* User.
* @param \Drupal\group\Entity\GroupInterface $training
* Training.
* @param \Drupal\opigno_module\Entity\OpignoModule $module
* Module.
*
* @return array
* Render array.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function trainingModule(UserInterface $user, GroupInterface $training, OpignoModule $module) {
$content = [];
$content[] = $this
->buildModuleDetails($user, $training, NULL, $module);
$content['#attached']['library'][] = 'opigno_statistics/user';
return $content;
}
/**
* Builds render array for a user course statistics page.
*/
public function course(UserInterface $user, GroupInterface $training, GroupInterface $course) {
$content = [];
$content[] = $this
->buildCourseDetails($user, $training, $course);
$content['#attached']['library'][] = 'opigno_statistics/user';
return $content;
}
/**
* Builds render array for a user training statistics page.
*/
public function training(UserInterface $user, GroupInterface $group) {
$content = [];
$content[] = $this
->buildTrainingDetails($user, $group);
$content['#attached']['library'][] = 'opigno_statistics/user';
return $content;
}
/**
* Builds render array for a user statistics index page.
*
* @param \Drupal\user\UserInterface $user
* User.
*
* @return array
* Render array.
*/
public function index(UserInterface $user) {
$moduleHandler = \Drupal::service('module_handler');
$content = [];
$content[] = $this
->buildUserInfo($user);
$content[] = $this
->buildBadges($user);
if ($moduleHandler
->moduleExists('opigno_skills_system') && !empty($skills = $this
->buildSkillsList($user))) {
$library_exists = file_exists('libraries/vis/dist/vis.js') && file_exists('libraries/vis/dist/vis.css');
if ($library_exists && \Drupal::service('library.discovery')
->getLibraryByName('opigno_skills_system', 'opigno_skills_using_vis')) {
$content['#attached']['library'][] = 'opigno_skills_system/opigno_skills_using_vis';
$content['#attached']['library'][] = 'opigno_skills_system/opigno_skills_entity';
foreach ($skills as $target_skill => $tree) {
$html = [
'#markup' => '<div id="opigno-skills-tree-' . $target_skill . '"></div>',
];
$tree_name = '(empty)';
$term_storage = \Drupal::entityTypeManager()
->getStorage('taxonomy_term');
$target_skill_entity = $term_storage
->load($target_skill);
if ($target_skill_entity) {
$tree_name = $target_skill_entity
->label();
}
$content[] = [
'#type' => 'container',
'#attributes' => [
'class' => [
'opigno_skills_tree_wrapper',
],
],
[
'#type' => 'table',
'#attributes' => [
'class' => [
'statistics-table',
'statistics-graph',
'skills-list',
'table-striped',
],
],
'#header' => [
$this
->t('Skills tree "') . $tree_name . '"',
],
'#rows' => [
[
\Drupal::service('renderer')
->render($html),
],
],
],
];
$content[] = $this
->buildSkillsTable($user, array_keys($tree['skills']));
}
$content['#attached']['drupalSettings']['opigno_skills_tree'] = $skills;
}
else {
$message = $this
->t('"almende/vis" library is not installed. Please install it from <a href="@library">here</a> and place in <em>libraries/</em> folder', [
'@library' => 'https://github.com/almende/vis.git',
]);
$this
->messenger()
->addWarning($message);
}
}
$content[] = $this
->buildTrainingsList($user);
$content['#attached']['library'][] = 'opigno_statistics/user';
return $content;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
ControllerBase:: |
protected | property | The configuration factory. | |
ControllerBase:: |
protected | property | The current user service. | 1 |
ControllerBase:: |
protected | property | The entity form builder. | |
ControllerBase:: |
protected | property | The entity manager. | |
ControllerBase:: |
protected | property | The entity type manager. | |
ControllerBase:: |
protected | property | The form builder. | 2 |
ControllerBase:: |
protected | property | The key-value storage. | 1 |
ControllerBase:: |
protected | property | The language manager. | 1 |
ControllerBase:: |
protected | property | The module handler. | 2 |
ControllerBase:: |
protected | property | The state service. | |
ControllerBase:: |
protected | function | Returns the requested cache bin. | |
ControllerBase:: |
protected | function | Retrieves a configuration object. | |
ControllerBase:: |
private | function | Returns the service container. | |
ControllerBase:: |
protected | function | Returns the current user. | 1 |
ControllerBase:: |
protected | function | Retrieves the entity form builder. | |
ControllerBase:: |
protected | function | Retrieves the entity manager service. | |
ControllerBase:: |
protected | function | Retrieves the entity type manager. | |
ControllerBase:: |
protected | function | Returns the form builder service. | 2 |
ControllerBase:: |
protected | function | Returns a key/value storage collection. | 1 |
ControllerBase:: |
protected | function | Returns the language manager service. | 1 |
ControllerBase:: |
protected | function | Returns the module handler. | 2 |
ControllerBase:: |
protected | function |
Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait:: |
|
ControllerBase:: |
protected | function | Returns the state storage service. | |
LinkGeneratorTrait:: |
protected | property | The link generator. | 1 |
LinkGeneratorTrait:: |
protected | function | Returns the link generator. | |
LinkGeneratorTrait:: |
protected | function | Renders a link to a route given a route name and its parameters. | |
LinkGeneratorTrait:: |
public | function | Sets the link generator service. | |
LoggerChannelTrait:: |
protected | property | The logger channel factory service. | |
LoggerChannelTrait:: |
protected | function | Gets the logger for a specific channel. | |
LoggerChannelTrait:: |
public | function | Injects the logger channel factory. | |
MessengerTrait:: |
protected | property | The messenger. | 29 |
MessengerTrait:: |
public | function | Gets the messenger. | 29 |
MessengerTrait:: |
public | function | Sets the messenger. | |
RedirectDestinationTrait:: |
protected | property | The redirect destination service. | 1 |
RedirectDestinationTrait:: |
protected | function | Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url. | |
RedirectDestinationTrait:: |
protected | function | Returns the redirect destination service. | |
RedirectDestinationTrait:: |
public | function | Sets the redirect destination service. | |
StatisticsPageTrait:: |
protected | function | Builds circle indicator for a value. | |
StatisticsPageTrait:: |
protected | function | Builds render array for a score value. | |
StatisticsPageTrait:: |
protected | function | Builds render array for a status value. | |
StatisticsPageTrait:: |
protected | function | Builds value for the training progress block. | |
StatisticsPageTrait:: |
protected | function | Builds value with a indicator for the training progress block. | |
StatisticsPageTrait:: |
protected | function | Returns users with the training expired certification. | |
StatisticsPageTrait:: |
protected | function | Returns group content average statistics for certificated training. | |
StatisticsPageTrait:: |
protected | function | Returns training content data by each step. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. | |
UrlGeneratorTrait:: |
protected | property | The url generator. | |
UrlGeneratorTrait:: |
protected | function | Returns the URL generator service. | |
UrlGeneratorTrait:: |
public | function | Sets the URL generator service. | |
UrlGeneratorTrait:: |
protected | function | Generates a URL or path for a specific route based on the given parameters. | |
UserController:: |
protected | property | Database connection. | |
UserController:: |
protected | property | Date formatter. | |
UserController:: |
protected | property | Time. | |
UserController:: |
public | function | Loads a user course details with the AJAX. | |
UserController:: |
public | function | Loads module panel with a AJAX. | |
UserController:: |
public | function | Loads a user training details with the AJAX. | |
UserController:: |
public | function | Loads module panel with a AJAX. | |
UserController:: |
public | function | Builds render array for a user badges block. | |
UserController:: |
public | function | Builds render array for a user course details. | |
UserController:: |
protected | function | Build render array for a user module details. | |
UserController:: |
public | function | Builds render array for a user skills list. | |
UserController:: |
public | function | Builds render array for a user skills table. | |
UserController:: |
public | function | Builds render array for a user training details. | |
UserController:: |
public | function | Builds render array for a user trainings list. | |
UserController:: |
public | function | Builds render array for a user info block. | |
UserController:: |
public | function | Builds render array for a user course statistics page. | |
UserController:: |
public | function | Builds render array for a user course statistics page. | |
UserController:: |
public static | function |
Create. Overrides ControllerBase:: |
|
UserController:: |
protected | function | Returns max score that user can have in this module & activity. | |
UserController:: |
protected | function | Get last or best user attempt for Module. | |
UserController:: |
public | function | Builds render array for a user statistics index page. | |
UserController:: |
public | function | Builds render array for a user training statistics page. | |
UserController:: |
public | function | Builds render array for a user course statistics page. | |
UserController:: |
public | function | UserController constructor. |