learnosity-1.0.x-dev/src/LearnosityItemsInlineHandler.php
src/LearnosityItemsInlineHandler.php
<?php
namespace Drupal\learnosity;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Render\Markup;
/**
* The Learnosity Items Inline Handler.
*
* This handler allows you to add inline learnosity items to a node page. To use
* it, invoke hook_learnosity_inline_items() and return an indexed array of
* item references.
*
* @package Drupal\learnosity
*/
class LearnosityItemsInlineHandler implements ContainerInjectionInterface {
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* The entity type manager service.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The learnosity Sdk service.
*
* @var \Drupal\learnosity\LearnositySdk
*/
protected $learnosity;
/**
* The learnosity session handler.
*
* @var \Drupal\learnosity\LearnositySessionHandler
*/
protected $learnositySession;
/**
* The learnosity mappings handler.
*
* @var \Drupal\learnosity\LearnosityMappingsHandler
*/
protected $learnosityMappings;
/**
* Constructs a new LearnosityItemsInlineHandler object.
*
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\learnosity\LearnositySdk $learnosity
* The learnosity sdk.
* @param \Drupal\learnosity\LearnositySessionHandler $learnosity_session
* The learnosity session handler.
* @param \Drupal\learnosity\LearnosityMappingsHandler $learnosity_mappings
* The learnosity mappings handler.
*/
public function __construct(AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager, LearnositySdk $learnosity, LearnositySessionHandler $learnosity_session, LearnosityMappingsHandler $learnosity_mappings) {
$this->currentUser = $current_user;
$this->entityTypeManager = $entity_type_manager;
$this->learnosity = $learnosity;
$this->learnositySession = $learnosity_session;
$this->learnosityMappings = $learnosity_mappings;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('current_user'),
$container->get('entity_type.manager'),
$container->get('learnosity.sdk'),
$container->get('learnosity.session_handler'),
$container->get('learnosity.mappings_handler'),
);
}
/**
* Manipulates the view display to show inline learnosity items.
*
* @param array $build
* The current view build.
* @param \Drupal\Core\Entity\EntityInterface $node
* The node.
* @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
* The current view display.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*
* @see hook_node_view_alter()
*/
public function nodeViewAlter(array &$build, EntityInterface $node, EntityViewDisplayInterface $display) {
$view_modes = [
'full',
'default',
];
if (in_array($build['#view_mode'], $view_modes)) {
$inline_items = $this->getInlineItems($node, $display);
if (!empty($inline_items) && $this->currentUser->isAuthenticated()) {
$user = $this->entityTypeManager->getStorage('user')->load($this->currentUser->id());
$session_id = $this->learnositySession->init($this->learnosityMappings->get($node, 'activity_id'));
$build['#context'] = [
'entity' => $node,
'user_id' => $user->id(),
];
$signed_request = $this->learnosity->init('items', [
'activity_id' => $this->learnosityMappings->get($node, 'activity_id'),
'name' => $this->learnosityMappings->get($node, 'name'),
'rendering_type' => 'inline',
'type' => 'submit_practice',
'session_id' => $session_id,
'user_id' => $this->learnosityMappings->get($user, 'id'),
'items' => $inline_items,
'config' => [
'questions_api_init_options' => [
'attribute_overrides' => [
'instant_feedback' => TRUE,
],
'show_distractor_rationale' => [
'per_question' => 'incorrect',
'per_response' => 'always',
],
],
],
], $build['#context']);
// Make sure that session_id is always passed as part of the context
// for assessment items. We can use this to determine most of the
// contextual information. E.g user, activity etc.
$build['#context'] += [
'session_id' => $session_id,
];
// Load core learnosity drupal js file and pass signed request.
$build['#attached']['library'][] = 'learnosity/learnosity';
$build['#attached']['library'][] = 'learnosity/api.items';
$build['#attached']['library'][] = 'learnosity/learnosity.inline_items';
$build['#attached']['drupalSettings']['learnosity'] = [
'service' => 'items',
'signedRequest' => Markup::create($signed_request),
'context' => $this->getScalarContextValues($build['#context']),
];
}
}
}
/**
* Return a formatted list of inline items.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity.
*
* @return array
* The array of inline items ready to be rendered.
*/
protected function getInlineItems(EntityInterface $entity, EntityViewDisplayInterface $display) {
// Prepare the inline items. By default, it doesn't know where the inline
// items come from. Use this hook to prepare them.
$inline_items = \Drupal::moduleHandler()->invokeAll('learnosity_inline_items', [$entity, $display]);
// Make sure that that items are unique otherwise it can trigger an error
// with learnosity and it won't render.
$inline_items = array_unique($inline_items);
$items = [];
foreach ($inline_items as $item) {
$items[] = ['id' => $item, 'reference' => $item];
}
return $items;
}
/**
* Parse context and return scalar values.
*
* Only attach scalar values because arrays and objects should not be
* passed through javascript.
*
* @param array $context
* The current context.
*
* @return array
* The array of scalar values.
*/
protected function getScalarContextValues(array $context) {
$new_context = [];
foreach ($context as $key => $value) {
if (is_scalar($value)) {
$new_context[$key] = $value;
}
}
return $new_context;
}
}
