knowledge-8.x-1.x-dev/src/Service/CompetencyService.php
src/Service/CompetencyService.php
<?php
namespace Drupal\knowledge\Service;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Messenger\MessengerTrait;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\knowledge\KnowledgeCompetencyServiceInterface;
use Drupal\user\UserInterface;
/**
* Service for the Competency entity.
*/
class CompetencyService implements KnowledgeCompetencyServiceInterface {
use StringTranslationTrait;
use MessengerTrait;
/**
* The settings.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected $settings;
/**
* The competency storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $competencyStorage;
/**
* The user role storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $userRoleStorage;
/**
* The current user.
*
* @var \Drupal\user\UserInterface
*/
protected $currentUser;
/**
* Constructs a new CompetencyService object.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param mixed $string_translation
* The string translation service.
* @param mixed $messenger
* The messenger service.
* @param mixed $current_user
* The current user.
*/
public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager, $string_translation, $messenger, $current_user) {
$this->settings = $config_factory->get('knowledge.competency.settings');
$this->competencyStorage = $entity_type_manager->getStorage('knowledge_competency');
$this->userRoleStorage = $entity_type_manager->getStorage('user_role');
$this->setStringTranslation($string_translation);
$this->setMessenger($messenger);
$this->currentUser = $current_user;
}
/**
* {@inheritdoc}
*/
public function get() {
$setting = $this->settings->get('roles') ?? [];
usort($setting, [static::class, 'sort']);
return $setting;
}
/**
* {@inheritdoc}
*/
public function getUserCompetency($user_id) {
$query = $this->competencyStorage->getQuery();
$result = $query
->condition('user_id', $user_id)
->accessCheck(FALSE)
->execute();
$competency = NULL;
if (count($result) == 1) {
$competency = $this->competencyStorage->load(current($result));
}
if (count($result) == 0) {
$competency = $this->competencyStorage->create([
'user_id' => $user_id,
]);
}
return $competency;
}
/**
* {@inheritdoc}
*/
public function getRoleIds() {
$roles = $this->get();
$role_ids = [];
foreach ($roles as $role) {
$role_ids[] = $role['role'];
}
return $role_ids;
}
/**
* {@inheritdoc}
*/
public function hasRoleOrBetter($role, $user_roles) {
if (in_array($role, $user_roles)) {
return TRUE;
}
$roles = $this->getRoleIds();
$role_index = array_search($role, $roles);
if ($role_index === FALSE) {
return FALSE;
}
foreach (range($role_index + 1, count($roles) - 1) as $i) {
if (in_array($roles[$i] ?? NULL, $user_roles)) {
return TRUE;
}
}
return FALSE;
}
/**
* {@inheritdoc}
*/
public function doRoleRemoval(UserInterface &$user) {
$user_roles = $user->getRoles(TRUE);
$removable_roles = $this->getRemovableRoles($user_roles);
foreach ($removable_roles as $role) {
$user->removeRole($role);
}
}
/**
* {@inheritdoc}
*/
public function doPreSave(&$roles, $orginal_roles) {
$role_settings = $this->get();
$sorted_roles = $this->getRoleIds();
$existing_completed = [];
foreach ($orginal_roles as $role) {
$completed = $role['total'] == $role['correct'] && $role['approved'] != NULL;
if ($completed) {
$existing_completed[] = $role['role'];
}
}
$new_roles = [];
foreach ($roles as $role) {
$role_name = $role->role;
$complete = $role->total == $role->correct;
if (!$complete) {
continue;
}
$existing = in_array($role_name, $existing_completed);
if ($existing || $role->proposed != NULL) {
continue;
}
$new_roles[] = $role_name;
}
$completed_roles = [];
$settings = [];
foreach ($role_settings as $setting) {
$role = $setting['role'];
$settings[$role] = $setting;
$is_existing = in_array($role, $existing_completed);
$is_new = in_array($role, $new_roles);
$completed = !$is_existing && $is_new;
if ($completed) {
$completed_roles[] = $role;
}
elseif ($is_existing) {
continue;
}
else {
break;
}
}
foreach ($roles as $role) {
$role_name = $role->role;
$completed = in_array($role_name, $completed_roles);
if (!$completed) {
continue;
}
$action = $settings[$role_name]['action'] ?? '_none';
$now = time();
$curren_user_id = $this->currentUser->id();
switch ($action) {
case 'auto':
$role->proposed = $now;
$role->proposer = $curren_user_id;
$role->approved = $now;
$role->approver = $curren_user_id;
break;
case 'leader':
$role->proposed = $now;
$role->proposer = $curren_user_id;
break;
case '_none':
default:
$role->proposed = $now;
$role->approved = $now;
break;
}
}
}
/**
* {@inheritdoc}
*/
public function doPostSave($user, $roles, $orginal_roles) {
$approved_roles = [];
foreach ($roles as $role) {
if ($role['approved'] != NULL) {
$approved_roles[] = $role['role'];
}
}
$orginal_approved_roles = [];
foreach ($orginal_roles as $role) {
if ($role['approved'] != NULL) {
$orginal_approved_roles[] = $role['role'];
}
}
$new_approved_roles = array_diff($approved_roles, $orginal_approved_roles);
$settings = $this->get();
$role_ids = $this->getRoleIds();
$save_user = FALSE;
$user_roles = $user->getRoles(TRUE);
foreach ($settings as $setting) {
$role = $setting['role'];
if (!in_array($role, $new_approved_roles)) {
continue;
}
$promote = $setting['promote'] ?? '_none';
$promote_role_id = NULL;
switch ($promote) {
case 'self':
$needs_role = !$this->hasRoleOrBetter($role, $user_roles);
if ($needs_role) {
$user->addRole($role);
$promote_role_id = $role;
$save_user = TRUE;
}
break;
case 'next':
$next_role = $role_ids[array_search($role, $role_ids) + 1] ?? NULL;
if (!is_null($next_role)) {
$needs_role = !$this->hasRoleOrBetter($next_role, $user_roles);
if ($needs_role) {
$user->addRole($next_role);
$promote_role_id = $next_role;
$save_user = TRUE;
}
}
break;
case '_none':
default:
break;
}
}
if ($save_user) {
$user->save();
$promote_role = $this->userRoleStorage->load($promote_role_id);
$this->messenger()->addMessage($this->t('%user was promoted to %role.', [
'%role' => $promote_role->label(),
'%user' => $user->getDisplayName(),
]));
}
}
/**
* {@inheritdoc}
*/
public function getPromotionRole($role_id) {
$roles = $this->get();
$role_ids = $this->getRoleIds();
$role_index = array_search($role_id, $role_ids);
if ($role_index === FALSE) {
return NULL;
}
$next_role = $role_ids[$role_index + 1] ?? NULL;
$settings = $this->get();
$role_settings = [];
foreach ($settings as $setting) {
$role_settings[$setting['role']] = $setting;
}
$promote = $role_settings[$role_id]['promote'] ?? '_none';
switch ($promote) {
case 'self':
return $role_id;
case 'next':
return $next_role;
case '_none':
default:
return NULL;
}
}
/**
* Get the roles that can be removed.
*
* @param array $user_roles
* The user roles.
*
* @return array
* The roles that can be removed.
*/
private function getRemovableRoles($user_roles) {
$removable_roles = [];
$best_role = NULL;
$roles = $this->getRoleIds();
foreach ($roles as $index => $role) {
if (in_array($role, $user_roles)) {
if (!is_null($best_role)) {
$removable_roles[] = $best_role;
}
$best_role = $role;
}
}
return $removable_roles;
}
/**
* Callback for usort.
*/
private static function sort($a, $b) {
if ($a['weight'] == $b['weight']) {
return 0;
}
return ($a['weight'] < $b['weight']) ? -1 : 1;
}
}
