course.module in Course 3.x
Same filename and directory in other branches
course.module Core functionality for Courses.
File
course.moduleView source
<?php
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Access\AccessResultForbidden;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Render\Element;
use Drupal\Core\Session\AccountInterface;
use Drupal\course\Entity\Course;
use Drupal\course\Entity\CourseObject;
use Drupal\course\Entity\CourseType;
use Drupal\field\Entity\FieldConfig;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
/**
* @file course.module
* Core functionality for Courses.
*/
// Course exporting functions
require_once 'includes/course.exporting.inc';
/**
* Implements hook_menu().
*/
function course_menu() {
$items['node/%course/object/%course_object/%ctools_js/nav'] = array(
'page callback' => 'course_ajaj_fulfullment_check',
'access callback' => TRUE,
'type' => MENU_CALLBACK,
'page arguments' => array(
1,
3,
5,
),
);
if (Drupal::moduleHandler()
->moduleExists('devel_generate')) {
$items['admin/config/development/generate/course'] = array(
'title' => 'Generate course',
'description' => 'Generate a given number of courses and object.',
'access arguments' => array(
'administer course',
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'course_generate_form',
),
'file' => 'course.devel.inc',
);
}
return $items;
}
/**
* Implements hook_course_handlers().
*
* @see course_menu()
* @see course_settings_overview()
*/
function course_course_handlers() {
return array(
'context' => array(
'node' => array(
'callback' => 'course_context',
),
),
);
}
/**
* Get course object handlers.
*
* @return array
*/
function course_get_handlers() {
/* @var $pluginManager CourseObjectPluginManager */
$pluginManager = Drupal::service('plugin.manager.course.object');
$plugins = $pluginManager
->getDefinitions();
return $plugins;
}
/**
* Get course outline handlers.
*
* @return array
*/
function course_get_outline_handlers() {
/* @var $pluginManager CourseOutlinePluginManager */
$pluginManager = Drupal::service('plugin.manager.course.outline');
$plugins = $pluginManager
->getDefinitions();
return $plugins;
}
/**
* Fulfillment check callback.
*
* This function is polled from nav.js to check remote fulfillments for external
* learning objects.
*/
function course_ajaj_fulfullment_check($node, $courseObject, $js = FALSE) {
global $user;
$account = $user;
// @todo most implements pull the current user
$courseObject
->poll();
if (course_node_is_course($node)) {
course_set_context($node);
}
module_load_include('inc', 'course', 'includes/course.block');
course_get_course($node);
$block = block_load('course', 'navigation');
$block_rend = _block_render_blocks(array(
$block,
));
drupal_json_output(array(
'content' => $block_rend['course_navigation']->content['#markup'],
'complete' => $courseObject
->getFulfillment($account)
->isComplete(),
));
}
/**
* Start an editing session for this course. Populate the session from
* persistent storage.
*
* @param Course $course
* A Course.
*/
function course_editing_start($course) {
if (empty($_SESSION['course'][$course
->id()]['editing'])) {
// Start editing cache from what we have in DB.
foreach ($course
->getObjects() as $courseObject) {
$_SESSION['course'][$course
->id()]['editing'][$courseObject
->id()] = $courseObject
->getOptions();
}
}
}
/**
* Menu title handler for the Take course tab.
*
* @return string
* "Review course" or "Take course", depending on the current user's
* completion status.
*/
function course_take_title($node) {
global $user;
$report = course_enrollment_load($node, $user);
return $user->uid > 1 && isset($report->complete) && $report->complete ? t('Review course') : t('Take course');
}
/**
* Menu access callback to determins if the take course button should display
* on the course node.
*
* This differs from course_access_course('take', ) as it only returns a boolean.
*
* @param object $node
* The course node.
*
* @see course_uc_token_values()
*/
function course_take_course_menu_access($node) {
global $user;
$courses =& drupal_static(__FUNCTION__, array());
if (!isset($courses[$node
->id()])) {
// Allow modules to restrict menu access to the take course tab.
$hooks = Drupal::moduleHandler()
->invokeAll('course_has_take', $node, $user);
$courses[$node
->id()] = !in_array(FALSE, $hooks);
}
return $courses[$node
->id()];
}
/**
* Callback for checking course settings permission.
*/
function course_settings_access($node) {
return $node
->access('update');
}
/**
* Saves course objects.
*
* @param CourseObject[] $objects
* An array of course object definitions.
* @param Course $course
* (optional) An instantiated Course, from course_get_course().
*/
function course_save_objects(array $objects, Course $course = NULL) {
foreach ($objects as $object) {
// Check if this course object already exists in the database.
if (isset($object->coid)) {
// Check if this object does not belong to the current node.
if ($object->cid != $course
->getCourse()
->id()) {
// We are importing or cloning. Ensure the necessary keys are empty,
// in order to prepare a new object using this object's definitions.
$unset = array(
'coid',
'cid',
'uuid',
'uniqid',
);
foreach ($unset as $key) {
if (isset($object->{$key})) {
unset($object->{$key});
}
}
// Replace the nid key, to properly associate the current course node
// with this course object.
$object->cid = $course
->getCourse()
->id();
}
}
$object
->save();
}
}
/**
* Un-enroll the user.
*
* Deletes course report entries, course enrollments, and object fulfillment
* records.
*
* @deprecated Use Course::unEnroll($account);
*
* @param Course $node
* A course node.
* @param AccountInterface $user
* A user.
*/
function course_unenroll(Course $course, AccountInterface $account) {
return $course
->unEnroll($account);
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Add third party settings to the node type form.
*/
function course_form_node_type_form_alter(&$form, FormStateInterface $form_state) {
$node = $form_state
->getFormObject()
->getEntity();
// Alter the node type's configuration form to add our setting.
$form['course'] = array(
'#type' => 'details',
'#title' => t('Course settings'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#access' => Drupal::currentUser()
->hasPermission('administer course'),
'#group' => 'additional_settings',
);
$form['course']['course_enabled'] = array(
'#title' => t('Use as course type'),
'#type' => 'checkbox',
'#default_value' => $node
->getThirdPartySetting('course', 'enabled'),
'#description' => t('This content type will have %course functionality.', array(
'%course' => 'Course',
)),
);
// Configurable date fields.
// @todo D8
if (FALSE && Drupal::moduleHandler()
->moduleExists('date')) {
$options = array();
$options[0] = t('<Not specified>');
$fields = field_info_fields();
foreach ($fields as $field) {
if ($field['module'] == 'date') {
foreach ($field['columns'] as $column => $value) {
if (!empty($field['bundles']['node']) && in_array($form['#node_type']->type, $field['bundles']['node']) && in_array($column, array(
'value',
'value2',
))) {
$position = $column == 'value' ? 'From' : 'To';
// Use the same label pattern as date_api_fields() for consistency
// with Views, and in case we support other date options than
// content date fields.
$info = field_info_instance('node', $field['field_name'], $form['#node_type']->type);
$label = t('Content: !label (!name) - @position date', array(
'!label' => $info['label'],
'!name' => $field['field_name'],
'@position' => $position,
));
#$key = "{$field['field_name']}[0]['{$column}']";
$key = serialize(array(
'field' => $field['field_name'],
'value' => $column,
));
$options[$key] = $label;
}
}
}
}
$date_settings_fs = array(
'#type' => 'fieldset',
'#title' => t('Date Settings Fieldset'),
'#title_display' => 'invisible',
'#collapsible' => FALSE,
'#collapsed' => FALSE,
'#states' => array(
'visible' => array(
':input[name="course_use"]' => array(
'checked' => TRUE,
),
),
),
);
$date_settings_fs['course_start_date'] = array(
'#title' => t('Field to use for enduring-course start date'),
'#description' => t('Select the field to use for enduring-course start date.'),
'#type' => 'select',
'#options' => $options,
'#default_value' => variable_get("course_start_date_{$form['#node_type']->type}", 0),
'#prefix' => '<h3>' . t('Enduring course dates') . '</h3>',
);
$date_settings_fs['course_expiration_date'] = array(
'#title' => t('Field to use for enduring-course expiration date'),
'#description' => t('Select the field to use for enduring-course expiration date.'),
'#type' => 'select',
'#options' => $options,
'#default_value' => variable_get("course_expiration_date_{$form['#node_type']->type}", 0),
);
// Live course dates.
$date_settings_fs['course_live_from_date'] = array(
'#title' => t('Field to use for live-course start date'),
'#description' => t('Select the field to use for live-course start date.'),
'#type' => 'select',
'#options' => $options,
'#default_value' => variable_get("course_live_from_date_{$form['#node_type']->type}", 0),
'#prefix' => '<h3>' . t('Live course dates') . '</h3>',
);
$date_settings_fs['course_live_to_date'] = array(
'#title' => t('Field to use for live-course end date'),
'#description' => t('Select the field to use for live-course end date.'),
'#type' => 'select',
'#options' => $options,
'#default_value' => variable_get("course_live_to_date_{$form['#node_type']->type}", 0),
);
$form['course']['date_settings_fs'] = $date_settings_fs;
}
$form['#entity_builders'][] = 'course_form_node_type_edit_form_builder';
}
/**
* Set third party course setting on form submit.
*/
function course_form_node_type_edit_form_builder($entity_type, NodeType $node_type, &$form, FormStateInterface $form_state) {
if ($form_state
->getValue('course_enabled')) {
$node_type
->setThirdPartySetting('course', 'enabled', $form_state
->getValue('course_enabled'));
return;
}
$node_type
->unsetThirdPartySetting('course', 'enabled');
}
/**
* Generic Course IFrame function.
*
* @param string $url
* An iframe HTML element src attribute.
* @param string $height
* A string representing an iframe height.
* @param string $class
* A HTML class attribute for the iframe.
*/
function course_iframe($url = NULL, $height = '600px', $class = NULL) {
$style = 'border:none; margin:0; width:100%; height:' . $height . ';';
// Add JS to resize parent frame. This assumes additional JS on the targeted iframe content.
// @todo
// drupal_add_js(drupal_get_path('module', 'course') . '/js/resizeframe.js');
return [
'#type' => 'html_tag',
'#tag' => 'iframe',
'#attributes' => [
'id' => 'course-viewer',
'src' => $url
->toString(),
'class' => [],
'scrolling' => 'no',
'frameborder' => 'no',
'onload' => 'resizeFrame(this);',
'style' => $style,
],
];
}
/**
* Get a course object by its unique identifier (sessioned course object).
*
* @param string $uniqid
* Unique identifier.
*
* @return CourseObject|FALSE
*/
function _course_get_course_object_by_uniqid($uniqid) {
if (!empty($_SESSION['course'])) {
foreach ($_SESSION['course'] as $cid => $session) {
if (isset($session['editing']) && is_array($session['editing'])) {
foreach ($session['editing'] as $coid => $object) {
if ($coid == $uniqid) {
return CourseObject::create($object);
}
}
}
}
}
return FALSE;
}
/**
* Get a course object by its identifier.
*
* @todo move to Storage?
*
* @param int $coid
* The numeric or temporary ID of the course object.
*
* @return CourseObject|FALSE
* A loaded CourseObject or FALSE if no object found.
*/
function course_get_course_object_by_id($coid) {
if (!is_numeric($coid)) {
return _course_get_course_object_by_uniqid($coid);
}
$courseObject = CourseObject::load($coid);
if ($courseObject) {
return $courseObject;
}
return FALSE;
}
/**
* Find a course object by module, type, instance, and optionally course.
*
* If course is provided and an instance exists in two courses, the object
* returned will be the object in the requested course. If a course is not
* provided, the object returned will be in the context of the current course.
*
* @param string $object_type
* The object type belonging to the module.
* @param string $instance
* The course object instance ID, FROM {course_object}.instance.
* @param Course $course
* The Course to pass to the CourseObject instantiation.
*
* @todo move to Storage?
*
* @return CourseObject
*/
function course_get_course_object(string $object_type, $instance, Course $course = NULL) {
$search = [
'object_type' => $object_type,
'instance' => $instance,
];
if (isset($course)) {
$search['cid'] = $course
->id();
}
$entities = Drupal::entityTypeManager()
->getStorage('course_object')
->loadByProperties($search);
if ($entities) {
return reset($entities);
}
return NULL;
}
/**
* Get the Course that a Node references.
*
* @todo Allow any field to be used that references a "Course" entity.
*
* @param Node $node
* The node object.
* @param stdClass $account
* The user with which to instantiate course objects and fulfillment.
*
* @return Course|boolean
* The Course entity, or FALSE if provided node was not a Course.
*/
function course_get_course(Node $node) {
if (course_node_is_course($node)) {
if ($course = $node->course->entity) {
return $course;
}
}
return FALSE;
}
/**
* Find the Entity that a Course is attached to.
*
* @param Course $course
* @param string $entity_type
*
* @return Node
*/
function course_get_attached(Course $course, $entity_type = 'node') {
$nids = Drupal::entityQuery($entity_type)
->condition('course', $course
->id())
->execute();
if ($nids) {
return Node::load(reset($nids));
}
}
/**
* Implements hook_views_plugins().
*/
function course_views_plugins() {
return array(
'argument validator' => array(
'course' => array(
'title' => t('Course'),
'handler' => 'views_plugin_argument_validate_course',
'path' => drupal_get_path('module', 'course') . '/views/plugins',
),
),
);
}
/**
* Implements hook_views_api().
*/
function course_views_api() {
return array(
'api' => 3,
'path' => drupal_get_path('module', 'course') . '/views',
);
}
/**
* Implements hook_entity_extra_field_info().
*/
function course_entity_extra_field_info() {
$extra = array();
$course_types = CourseType::loadMultiple();
foreach ($course_types as $bundle => $course_type) {
$extra['course'][$bundle]['display']['course'] = array(
'label' => t('Take course link'),
'weight' => 0,
);
$extra['course'][$bundle]['display']['course_messages'] = array(
'label' => t('Course messages'),
'weight' => 0,
);
}
$extra['course_object']['course_object']['display']['course_outline_image'] = array(
'label' => t('Status image'),
'weight' => 0,
);
$extra['course_object']['course_object']['display']['course_outline_link'] = array(
'label' => t('Link to the course object'),
'weight' => 1,
);
$extra['course_object']['course_object']['display']['course_outline_status'] = array(
'label' => t('Status text'),
'weight' => 2,
);
return $extra;
}
/**
* Implements hook_preprocess_page().
*/
function course_preprocess_page(&$variables) {
// @todo broken
return;
if (arg(2) == 'take') {
$regions = variable_get('course_disable_regions', array());
foreach ($regions as $key => $region) {
if ($region) {
unset($variables[$region]);
}
}
}
if ($course = course_get_context()) {
// Back/next buttons?
//$variables['content'] .= 'sdfsdfsd';
}
}
/**
* Implements hook_tokens().
*/
function course_tokens($type, $tokens, array $data = [], array $options = [], BubbleableMetadata $bubbleable_metadata) {
if ($type == 'course_enrollment' && !isset($data['course_enrollment']) && isset($data['course'], $data['user']) && ($course_enrollment = $data['course']
->getEnrollment($data['user']))) {
$data['course_enrollment'] = $course_enrollment;
return token_tokens('course_enrollment', $tokens, $data, $options, $bubbleable_metadata);
}
}
/**
* Implements hook_init().
*
* Detect and set course context. Adds javascript for course objects that
* require polling. Hack for #1902104.
*/
function course_init() {
if (class_exists('Course') && $courseNode) {
// Check that Course exists for a special use case where Autoload hasn't yet
// cached the Course class.
$course = course_get_course($courseNode);
if ($course && ($active = $course
->getActive())) {
if ($active
->hasPolling()) {
drupal_add_js(array(
'courseAjaxNavPath' => url('course/' . $courseNode
->id() . '/object/' . $course
->getActive()
->id() . '/ajax/nav'),
), array(
'type' => 'setting',
'scope' => JS_DEFAULT,
));
}
}
}
}
/**
* Course content handler callback.
*/
function course_context() {
$route_match = Drupal::routeMatch();
if (in_array($route_match
->getRouteName(), [
'course.take',
'course.object',
])) {
$course = $route_match
->getParameter('course');
course_set_context($course);
}
}
/**
* Implements hook_course_access().
*
* Block enrollments when a course has either not yet started or is expired.
*/
function course_course_access(Course $entity, $operation, AccountInterface $account) {
if (!in_array($operation, [
'take',
'enroll',
])) {
return;
}
$request_time = Drupal::time()
->getRequestTime();
$enrollment = $entity
->getEnrollment($account);
if (!$entity
->get('course_date')
->isEmpty() && in_array($operation, [
'take',
'enroll',
])) {
$date = $entity
->get('course_date')
->getValue();
$course_open = new DrupalDateTime($date[0]['value'], 'UTC');
$course_close = new DrupalDateTime($date[0]['end_value'], 'UTC');
$now = DrupalDateTime::createFromTimestamp($request_time);
$course_not_open = $course_open
->diff($now)->invert;
$course_closed = !$course_close
->diff($now)->invert;
$formatter = Drupal::service('date.formatter');
// Both enroll and take course blockers.
if ($date[0]['value'] && $course_not_open) {
$message = t('This course opens on %date.', [
'%date' => $formatter
->format($course_open
->getTimestamp()),
]);
return [
'course_notopen' => AccessResult::forbidden((string) $message),
];
}
if ($date[0]['end_value'] && $course_closed) {
$message = t('This course closed on %date.', [
'%date' => $formatter
->format($course_close
->getTimestamp()),
]);
return [
'course_closed' => AccessResult::forbidden((string) $message),
];
}
}
if ($operation == 'enroll') {
if (!$entity
->access('view', $account)) {
return array(
'course_denied' => AccessResult::forbidden('You do not have permission to enroll into this course'),
);
}
if (!empty($entity->course['live_from_date']) && Drupal::time()
->getRequestTime() > $entity->course['live_from_date']) {
return array(
'course_live_started' => array(
'success' => FALSE,
'message' => t('This live activity started on %date and is no longer available for enrollments.', array(
'%date' => Drupal::service('date.formatter')
->format($entity->course['live_from_date'], 'long'),
)),
),
);
}
if ($account
->isAnonymous()) {
$options = \Drupal::destination()
->getAsArray();
$message = t('Please @login or @register to take this course.', array(
'@login' => Link::createFromRoute(t('login'), 'user.login', $options)
->toString(),
'@register' => Link::createFromRoute(t('register'), 'user.register', $options)
->toString(),
));
return [
'course_noanon' => AccessResult::forbidden((string) $message),
];
}
return [
'course_enroll' => AccessResult::allowedIf($account
->hasPermission('enroll course')),
];
}
if ($operation == 'take') {
if (!$entity
->access('view', $account)) {
return [
'course_node_access' => AccessResult::forbidden('You do not have permission to take this course.'),
];
}
if ($enrollment) {
if ($enrollment
->get('enroll_end')
->getString() > 0 && $request_time > $enrollment
->get('enroll_end')
->getString()) {
return [
'course_enrollment_expired' => AccessResult::forbidden('Sorry, your enrollment has expired for this course.'),
];
}
return [
'course_take' => AccessResult::allowedIf($account
->hasPermission('take course')),
];
}
else {
return [
'course_not_enrolled' => AccessResult::forbidden('Sorry, you must first enroll in this course.'),
];
}
}
}
/**
* Implements hook_user_delete().
*
* Clean up course reports and fulfillments for a deleted user.
*/
function course_user_delete(AccountInterface $account) {
$enrollments = Drupal::entityTypeManager()
->getStorage('course_enrollment')
->loadByProperties([
'uid' => $account
->id(),
]);
foreach ($enrollments as $enrollment) {
$enrollment
->delete();
}
}
/**
* Implements hook_theme().
*
* @todo none of this works in D8
*/
function course_theme() {
return array(
'course' => [
'render element' => 'elements',
],
'course_outline' => array(
'file' => 'includes/course.theme.inc',
'variables' => array(
'node' => NULL,
'items' => NULL,
),
),
'course_take_course_button' => array(
'variables' => array(
'course' => NULL,
'title' => NULL,
),
),
);
}
/**
* Prepares variables for course templates.
*
* Default template: course.html.twig.
*
* @param array $variables
* An associative array containing:
* - elements: An associative array containing rendered fields.
* - attributes: HTML attributes for the containing element.
*/
function template_preprocess_course(array &$variables) {
/** @var Course $course */
$course = $variables['elements']['#course'];
$variables['course'] = $course;
// Helpful $content variable for templates.
$variables['content'] = [];
foreach (Element::children($variables['elements']) as $key) {
$variables['content'][$key] = $variables['elements'][$key];
}
}
/**
* Gets the course context.
*
* @return Course
* The Course context, or NULL.
*/
function course_get_context() {
return course_set_context();
}
/**
* Sets a course context.
*
* @return Course
*/
function course_set_context(Course $course = NULL, $clear = FALSE) {
$stored_course =& drupal_static(__FUNCTION__);
if ($clear) {
$stored_course = NULL;
}
if (!empty($course)) {
$stored_course = $course;
}
return !empty($stored_course) ? $stored_course : NULL;
}
/**
* Get the course node automatically, or from optional query parameters.
*
* @param string $module
* The implementing course object provider module name.
* @param string $object_type
* The course object key as defined by hook_course_handlers().
* @param string $instance
* A key used internally by the implementing course object provider module,
* to identify an instance of *something* used by this course object type.
* @param bool $no_set
* Do not set the context (active course), just return it.
* @param bool $flush
* Flush the static cache. By default, course_determine_context will stop
* processing once a course is found, and continue to return it.
*
* @return mixed
* A course node or NULL if course context not found.
*/
function course_determine_context($object_type = NULL, $instance = NULL, $no_set = FALSE) {
$lookup =& drupal_static('course_determine_context', array());
if (isset($lookup["{$object_type}:{$instance}"])) {
return $lookup["{$object_type}:{$instance}"];
}
$context = NULL;
// Determine the course node based on passed query parameters.
$result = Drupal::database()
->query("SELECT cid FROM {course_object} WHERE instance = :instance AND object_type = :object_type", array(
':instance' => $instance,
':object_type' => $object_type,
));
$cids = array();
while ($course_outline = $result
->fetch()) {
$cids[] = $course_outline->cid;
}
if (count($cids) > 1) {
if (!empty($_SESSION['course']['active']) && in_array($_SESSION['course']['active'], $cids)) {
// The active course in the session is one of the courses this object
// belongs to.
$context = Course::load($_SESSION['course']['active']);
}
else {
// No active course, or no match. We have to guess since we're accessing
// this course material outside of the course.
$context = Course::load($cids[0]);
}
}
elseif ($cids) {
// We don't have an active session (or, the course in the active session
// didn't contain this course object). So we just guess the first one.
$context = Course::load($cids[0]);
}
if ($no_set) {
// Callee just wants context.
$lookup["{$object_type}:{$instance}"] = $context;
return $context;
}
elseif ($context) {
// Set the active course and static cache it.
$_SESSION['course']['active'] = $context->cid;
$lookup["{$object_type}:{$instance}"] = $context;
return $context;
}
}
/**
* Implements hook_course_admin_paths().
*
* Expose the course object configuration as an administrative path.
*
* @todo https://www.drupal.org/node/2224207
*/
function course_admin_paths() {
return array(
'node/*/object/*/options' => TRUE,
);
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function course_form_field_config_edit_form_alter(&$form, FormStateInterface $form_state) {
$field = $form_state
->getFormObject()
->getEntity();
if ($field
->getTargetEntityTypeId() != 'course_enrollment') {
return;
}
$form['third_party_settings']['course']['show_field'] = array(
'#type' => 'checkbox',
'#title' => t('Show this field on enrollment.'),
'#default_value' => $field
->getThirdPartySetting('course', 'show_field', TRUE),
'#description' => t('If checked, this field will be presented when starting a course.'),
);
}
/**
* Implements hook_entity_field_access().
*
* Don't show the user fields that weren't marked as enrollment fields.
*/
function course_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
if ($operation == 'edit' && $field_definition
->getTargetEntityTypeId() == 'course_enrollment') {
if (is_a($field_definition, FieldConfig::class)) {
/* @var $field_definition FieldConfig */
if (!$field_definition
->getThirdPartySetting('course', 'show_field')) {
return AccessResult::forbidden('enrollment_user_field');
}
}
elseif (!$account
->hasPermission('administer course enrollments')) {
// Hide fields like timestamp, status, etc.
return AccessResultForbidden::forbidden();
}
}
return AccessResult::neutral();
}
/**
* Implements hook_course_credit_map_options().
*/
function course_course_credit_map_options() {
$ret = array();
$instances = field_info_instances('course_enrollment', 'course_enrollment');
foreach ($instances as $field_name => $instance_info) {
$field_info = field_info_field($field_name);
if ($options = list_allowed_values($field_info)) {
$ret['course_enrollment']['mappers'][$field_name]['title'] = $instance_info['label'];
$ret['course_enrollment']['mappers'][$field_name]['options'] = $options;
}
}
return $ret;
}
/**
* Implements hook_course_credit_map().
*
* Figure out if the user's enrollment fields make them eligible for credit.
*/
function course_course_credit_map(Course $course, AccountInterface $account, $mappings) {
if ($enrollment = $course
->getEnrollment($account)) {
if (!empty($mappings['course_enrollment'])) {
foreach ((array) $mappings['course_enrollment'] as $field => $values) {
if (!empty($enrollment->{$field})) {
foreach ($enrollment->{$field}[LANGUAGE_NONE] as $item) {
if (in_array($item['value'], $values)) {
return TRUE;
}
}
}
}
}
}
}
/**
* Access callback for course objects menu tab.
*/
function _course_reports_access($node) {
return $node
->access('update') || Drupal::currentUser()
->hasPermission('access all course reports');
}
/**
* Can the user access the course administration pages?
*/
function course_admin_access() {
return Drupal::currentUser()
->hasPermission('administer course') || Drupal::currentUser()
->hasPermission('access course administration area');
}
/**
* Implements hook_page_attachments().
*/
function course_page_attachments(&$page) {
$page['#attached']['library'][] = 'course/styles';
}
function course_entity_bundle_info() {
$bundles['course_object_type']['whatever']['label'] = 'sdfsdf';
return $bundles;
}
Functions
Name | Description |
---|---|
course_admin_access | Can the user access the course administration pages? |
course_admin_paths | Implements hook_course_admin_paths(). |
course_ajaj_fulfullment_check | Fulfillment check callback. |
course_context | Course content handler callback. |
course_course_access | Implements hook_course_access(). |
course_course_credit_map | Implements hook_course_credit_map(). |
course_course_credit_map_options | Implements hook_course_credit_map_options(). |
course_course_handlers | Implements hook_course_handlers(). |
course_determine_context | Get the course node automatically, or from optional query parameters. |
course_editing_start | Start an editing session for this course. Populate the session from persistent storage. |
course_entity_bundle_info | |
course_entity_extra_field_info | Implements hook_entity_extra_field_info(). |
course_entity_field_access | Implements hook_entity_field_access(). |
course_form_field_config_edit_form_alter | Implements hook_form_FORM_ID_alter(). |
course_form_node_type_edit_form_builder | Set third party course setting on form submit. |
course_form_node_type_form_alter | Implements hook_form_FORM_ID_alter(). |
course_get_attached | Find the Entity that a Course is attached to. |
course_get_context | Gets the course context. |
course_get_course | Get the Course that a Node references. |
course_get_course_object | Find a course object by module, type, instance, and optionally course. |
course_get_course_object_by_id | Get a course object by its identifier. |
course_get_handlers | Get course object handlers. |
course_get_outline_handlers | Get course outline handlers. |
course_iframe | Generic Course IFrame function. |
course_init | Implements hook_init(). |
course_menu | Implements hook_menu(). |
course_page_attachments | Implements hook_page_attachments(). |
course_preprocess_page | Implements hook_preprocess_page(). |
course_save_objects | Saves course objects. |
course_settings_access | Callback for checking course settings permission. |
course_set_context | Sets a course context. |
course_take_course_menu_access | Menu access callback to determins if the take course button should display on the course node. |
course_take_title | Menu title handler for the Take course tab. |
course_theme | Implements hook_theme(). |
course_tokens | Implements hook_tokens(). |
course_unenroll Deprecated | Un-enroll the user. |
course_user_delete | Implements hook_user_delete(). |
course_views_api | Implements hook_views_api(). |
course_views_plugins | Implements hook_views_plugins(). |
template_preprocess_course | Prepares variables for course templates. |
_course_get_course_object_by_uniqid | Get a course object by its unique identifier (sessioned course object). |
_course_reports_access | Access callback for course objects menu tab. |