abstract class CourseObject in Course 8.2
Same name in this branch
- 8.2 src/Annotation/CourseObject.php \Drupal\course\Annotation\CourseObject
- 8.2 src/Entity/CourseObject.php \Drupal\course\Entity\CourseObject
Same name and namespace in other branches
- 8.3 src/Entity/CourseObject.php \Drupal\course\Entity\CourseObject
- 3.x src/Entity/CourseObject.php \Drupal\course\Entity\CourseObject
Parent abstract base class of all course objects.
Represents a course object in the database.
Also holds a fulfillment record if a user is given.
Plugin annotation
@ContentEntityType(
id = "course_object",
label = @Translation("Course object"),
label_collection = @Translation("Course objects"),
label_singular = @Translation("Course object"),
label_plural = @Translation("Course objects"),
label_count = @PluralTranslation(
singular = "@count course object",
plural = "@count course object fulfillments",
),
admin_permission = "administer course",
permission_granularity = "bundle",
bundle_label = @Translation("Course object type"),
bundle_entity_type = "course_object_type",
base_table = "course_object",
fieldable = TRUE,
field_ui_base_route = "entity.course_object_type.edit_form",
show_revision_ui = TRUE,
revision_table = "course_object_revision",
revision_data_table = "course_object_field_revision",
entity_keys = {
"id" = "coid",
"uid" = "uid",
"bundle" = "object_type",
"label" = "title"
},
revision_metadata_keys = {
"revision_user" = "revision_uid",
"revision_created" = "revision_timestamp",
"revision_log_message" = "revision_log"
},
handlers = {
"access" = "Drupal\course\Access\CourseObjectAccessControlHandler",
"permission_provider" = "Drupal\entity\UncacheableEntityPermissionProvider",
"storage" = "Drupal\course\Storage\CourseObjectStorage",
"view_builder" = "Drupal\course\View\CourseObjectViewBuilder",
"views_data" = "Drupal\views\EntityViewsData",
"form" = {
"default" = "Drupal\Core\Entity\ContentEntityForm",
"delete" = "Drupal\Core\Entity\ContentEntityDeleteForm",
},
}
)
Hierarchy
- class \Drupal\Core\Entity\EntityBase implements EntityInterface uses RefinableCacheableDependencyTrait, DependencySerializationTrait
- class \Drupal\Core\Entity\ContentEntityBase implements \Drupal\Core\Entity\IteratorAggregate, ContentEntityInterface, TranslationStatusInterface uses EntityChangesDetectionTrait, SynchronizableEntityTrait
- class \Drupal\course\Helper\CourseHandler
- class \Drupal\course\Entity\CourseObject
- class \Drupal\course\Helper\CourseHandler
- class \Drupal\Core\Entity\ContentEntityBase implements \Drupal\Core\Entity\IteratorAggregate, ContentEntityInterface, TranslationStatusInterface uses EntityChangesDetectionTrait, SynchronizableEntityTrait
Expanded class hierarchy of CourseObject
19 files declare their use of CourseObject
- course.module in ./
course.module - course.module Core functionality for Courses.
- Course.php in src/
Entity/ Course.php - CourseObjectAccessGrade.php in src/
Plugin/ course/ CourseObjectAccess/ CourseObjectAccessGrade.php - CourseObjectBookTestCase.php in modules/
course_book/ tests/ src/ Functional/ CourseObjectBookTestCase.php - CourseObjectBroken.php in src/
Object/ CourseObjectBroken.php
File
- src/
Entity/ CourseObject.php, line 72
Namespace
Drupal\course\EntityView source
abstract class CourseObject extends CourseHandler {
protected $accessMessages = array();
/**
* Override navigation links.
*
* @return array
* An array of navigation links. Keyed values will override matching items
* in Course::getNavigation().
*/
public function overrideNavigation() {
return array();
}
/**
* Specify whether fulfillment uses asynchronous polling.
*
* @return bool
* Whether this object uses polling. Defaults to FALSE.
*/
public function hasPolling() {
return FALSE;
}
/**
* Overrides a course outline list item.
*
* @param array $item
* A course outline list item. The structure mirrors an array element from
* the $items param from theme_item_list().
*/
public function overrideOutlineListItem(&$item) {
}
public function isActive() {
return $this
->getCourse()
->current()
->getId() == $this
->getId();
}
/**
* Define configuration elements and their defaults.
*
* Extended classes should call parent::optionsDefinition first to get the
* parent's configuration.
*/
public function optionsDefinition() {
$defaults = parent::optionsDefinition();
$defaults += array(
'uniqid' => NULL,
'nid' => NULL,
'title' => NULL,
'enabled' => 1,
'hidden' => 0,
'required' => 1,
'skippable' => 0,
'delete' => 0,
'delete_instance' => 0,
'grade_include' => 0,
'instance' => NULL,
'plugins' => array(),
'duration' => NULL,
'skippable' => 0,
'use_node_title' => 1,
);
return $defaults;
}
/**
* Default options form for all course objects.
*/
public function optionsForm(&$form, &$form_state) {
parent::optionsForm($form, $form_state);
$config = $this
->getOptions();
$form['header']['#markup'] = t("<h2>Settings for %t</h2>", array(
'%t' => $this
->getTitle(),
));
$form['uniqid'] = array(
'#type' => 'value',
'#value' => $this
->getId(),
);
$form['course_tabs']['#type'] = 'vertical_tabs';
$form['course_tabs']['#default_tab'] = 'edit-title';
$form['title'] = array(
'#title' => t('Title & description'),
'#type' => 'details',
'#group' => 'course_tabs',
'#weight' => 0,
);
$form['outline'] = array(
'#type' => 'details',
'#title' => t('Settings'),
'#group' => 'course_tabs',
'#weight' => 1,
);
$form['plugins']['access'] = array(
'#type' => 'details',
'#title' => 'Access',
'#group' => 'course_tabs',
'#weight' => 4,
);
$form['delete'] = array(
'#type' => 'details',
'#title' => 'Delete',
'#group' => 'course_tabs',
'#weight' => 5,
);
$form['title']['title'] = array(
'#title' => t('Title'),
'#type' => 'textfield',
'#description' => t('The title of this course object as it will appear to users in the course outline.'),
'#size' => 100,
'#default_value' => $config['title'],
'#group' => 'description',
'#required' => TRUE,
);
$form['outline']['enabled'] = array(
'#title' => t('Enabled'),
'#type' => 'checkbox',
'#description' => t('Enabled course objects will become part of the course. Uncheck this box if you are not using this course object.'),
'#default_value' => $config['enabled'],
);
$form['outline']['hidden'] = array(
'#title' => t('Visible in outline'),
'#type' => 'checkbox',
'#description' => t('Objects that are not visible will not be seen by the learner. Uncheck this box for course objects that you do not want the learner to see.'),
'#default_value' => !$config['hidden'],
'#group' => 'course',
);
$form['outline']['required'] = array(
'#title' => t('Completion required'),
'#type' => 'checkbox',
'#description' => t('Users must complete required objects. Uncheck this box if this is an optional course object.'),
'#default_value' => $config['required'],
);
$form['outline']['skippable'] = array(
'#title' => t('Skippable'),
'#type' => 'checkbox',
'#default_value' => $config['skippable'],
'#states' => array(
'visible' => array(
'#edit-required' => array(
'checked' => TRUE,
),
),
),
'#description' => t('Users can proceed past this object but it will still be required for course completion.'),
);
// Delete object
$form['delete']['delete_button'] = array(
'#value' => t('Delete'),
'#weight' => 999,
'#type' => 'submit',
'#submit' => array(
array(
$this,
'setDelete',
),
array(
$this,
'optionsSubmit',
),
),
'#limit_validation_errors' => array(),
);
// Only allow deletion of existing instances.
if (!empty($config['instance'])) {
$form['delete']['delete_instance'] = array(
'#title' => t('Also delete the referenced content.'),
'#type' => 'checkbox',
'#default_value' => $config['delete_instance'],
'#stats' => array(
'visible' => array(
'#edit-delete' => array(
'checked' => TRUE,
),
),
),
'#group' => 'delete',
);
// Check for multiple instances.
if (Drupal::database()
->query("SELECT count(coid) FROM {course_object} WHERE object_type = :object_type AND instance = :instance", array(
':object_type' => $config['object_type'],
':instance' => $config['instance'],
))
->fetchField() > 1) {
$form['delete']['delete_instance']['#description'] = t('<span class="error"><strong>WARNING</strong></span>: multiple course objects link to this instance. Deleting the instance might break the other course objects that use it.');
}
}
if ($this
->isGraded()) {
$form['grading'] = array(
'#title' => t('Grading'),
'#type' => 'details',
'#description' => t('Settings for graded objects.'),
'#group' => 'course_tabs',
'#weight' => 2,
);
$form['grading']['grade_include'] = array(
'#title' => t('Include in final course grade'),
'#description' => t('Include this grade result for calculation of the final course grade.<br/>Currently, only the last grade result per Course will be used.'),
'#default_value' => $config['grade_include'],
'#type' => 'checkbox',
);
}
// Bring in access plugin configuration.
$form['plugins']['#tree'] = TRUE;
$form['plugins']['access']['#title'] = t('Access');
$form['plugins']['access']['#description'] = t('By default, all required objects appearing before this object in the course outline must be completed before the user may access this object. Conditional access allows for additional conditions to be applied.');
$form['plugins']['access']['#type'] = 'details';
$pluginManager = Drupal::service('plugin.manager.course.object.access');
$plugins = $pluginManager
->getDefinitions();
foreach ($plugins as $key => $plugin) {
$form['plugins']['access']['#tree'] = TRUE;
$form['plugins']['access'][$key] = array(
'#title' => $plugin['label'],
'#type' => 'details',
'#tree' => TRUE,
'#open' => FALSE,
);
// Initialize access class.
/* @var $courseAccess CourseObjectAccessPluginBase */
$courseAccess = $pluginManager
->createInstance($key);
$courseAccess
->setCourseObject($this);
$courseAccess
->setType($key);
// Add access plugin form to our form.
$access_form = $access_form_state = array();
$form['plugins']['access'][$key] += $courseAccess
->optionsForm($access_form, $access_form_state);
}
// Update settings
$form['actions']['update'] = array(
'#value' => t('Update'),
'#weight' => 999,
'#type' => 'submit',
'#validate' => array(
array(
$this,
'optionsValidate',
),
),
'#submit' => array(
array(
$this,
'optionsSubmit',
),
),
);
}
/**
* Mark this object for deletion.
*/
public function setDelete(&$form, FormStateInterface $form_state) {
$form_state
->setValue('delete', 1);
if (!empty($form_state
->getUserInput()['delete_instance'])) {
$form_state
->setValue('delete_instance', $form_state
->getUserInput()['delete_instance']);
}
}
public function optionsValidate(&$form, FormStateInterface $form_state) {
// Pass validation to plugins.
// ctools_include('plugins');
// foreach (ctools_get_plugins('course', 'course_object_access') as $key => $plugin) {
// $values = & $form_state['values']['plugins']['access'][$key];
// $class = ctools_plugin_get_class($plugin, 'handler');
// $instance = new $class($values);
// $instance->setCourseObject($this);
// $instance->setType($key);
// $instance->optionsValidate($form['plugins']['access'][$key], $form_state['values']['plugins']['access'][$key]);
// }
}
/**
* Save object configs to cache.
*/
public function optionsSubmit(&$form, FormStateInterface $form_state) {
$uniqid = $this
->getId();
$course = $form_state
->getBuildInfo()['args'][0];
$cid = $course
->id();
// Start editing session.
course_editing_start($this
->getCourse());
// Flip 'visible' so it behaves like 'hidden'.
if ($form_state
->getValue('hidden')) {
$form_state
->setValue('hidden', $form_state
->getValue('hidden') != 1);
}
// Object-specific settings
$_SESSION['course'][$cid]['editing'][$uniqid] = $form_state
->getValues() + $_SESSION['course'][$cid]['editing'][$uniqid];
}
/**
* Get core options summary.
*
* @return array
* An associative array of summary keys and values.
*/
public function getOptionsSummary() {
$summary = parent::getOptionsSummary();
// Get options.
$options = $this
->getOptions();
// Enabled.
if ($options['enabled']) {
$summary['enabled'] = t('Enabled');
}
else {
$summary['enabled'] = '<span class="warning">' . t('Not enabled') . '</span>';
}
// Hidden.
if (!$options['hidden']) {
$summary['hidden'] = t('Visible in outline');
}
else {
$summary['hidden'] = '<span class="warning">' . t('Not visible in outline') . '</span>';
}
// Required.
if ($options['required']) {
$summary['required'] = t('Completion required');
if ($options['skippable']) {
$summary['skippable'] = '<span class="warning">' . t('Skippable') . '</span>';
}
}
else {
$summary['required'] = '<span class="warning">' . t('Completion not required') . '</span>';
}
// Instance edit link.
$editUrl = $this
->getEditUrl();
if (!empty($editUrl)) {
$text = t('Edit instance');
$summary['instance'] = Link::fromTextAndUrl($text, $editUrl)
->toString();
}
elseif ($this
->isTemporary()) {
$summary['instance'] = '<span class="warning">' . t('Save course to edit object') . '</span>';
}
// Instance view link.
$viewUrl = $this
->getViewUrl();
if (!empty($viewUrl)) {
$text = t('View instance');
$summary['instance_view'] = Link::fromTextAndUrl($text, $viewUrl)
->toString();
}
// Required.
if (!empty($options['delete'])) {
$dest = Url::fromRoute('course.object.restore', [
'course' => $options['cid'],
'course_object' => $this
->getId(),
], [
'attributes' => [
'class' => 'use-ajax',
],
]);
$text = t('Object will be removed from outline');
$restore_text = t('Restore this object to the course outline.');
if ($options['delete_instance']) {
$text = t('Object will be removed from outline, and related instance(s) will be deleted');
$restore_text = t('Restore this object and related instance(s) to the course outline.');
}
$restore = Link::fromTextAndUrl(t('Restore'), $dest, $restore_text)
->toString();
$summary['delete'] = '<span class="error">' . $text . '</span>';
$summary['restore'] = $restore;
}
return $summary;
}
/**
* Get all course object implementations of getOptionsSummary().
*
* @todo need plugins
*/
public function renderOptionsSummary() {
$summary = $this
->getOptionsSummary();
$out = [];
foreach ($summary as $key => $item) {
$out[$key]['#markup'] = $item;
}
return $out;
}
/**
* Get options, with session options, except weight, having precedence.
*/
public function getOptions() {
$options = parent::getOptions();
$sessionDefaults = array();
if (isset($options['cid']) && isset($options['coid']) && isset($_SESSION['course'][$options['cid']]['editing'][$options['coid']])) {
$sessionDefaults += array_filter((array) $_SESSION['course'][$options['cid']]['editing'][$options['coid']], array(
$this,
'optionFilter',
));
unset($sessionDefaults['weight']);
}
return array_merge($options, (array) $sessionDefaults);
}
private function optionFilter($a) {
return !is_null($a);
}
/**
* Take a course object.
*
* - Set the session of this course object being taken. This allows for
* non-node objects to be tracked.
* - Delegate the course object take functionality
*
* @return mixed
* HTML content or a redirect.
*/
public final function takeObject() {
$account = Drupal::currentUser();
$_SESSION['course']['active'] = $this
->getCourse()
->id();
$_SESSION['course'][$this
->getCourse()
->id()]['taking']['active'] = $this
->getId();
// Run access checks.
if ($this
->access('take')) {
// Grant access to external course object.
$this
->getFulfillment($account)
->grant();
// Record start date.
$this
->getFulfillment($account)
->save();
}
else {
// User can't access this object, revoke access.
$this
->getFulfillment($account)
->revoke();
return FALSE;
}
// If we're not displaying any content but we want to fire take() anyway, to
// let the course object know we sent the user.
$out = $this
->take();
$url = $this
->getTakeUrl();
switch ($this
->getTakeType()) {
case 'iframe':
return course_iframe($url);
case 'popup':
return "will popup {$url}";
case 'content':
return $out;
case 'redirect':
default:
// This URL should have already been url()'d (it might be external).
return new RedirectResponse($url
->toString());
}
}
/**
* How should this course object be executed?
*
* - iframe: display an iframe with getTakeUrl() in it
* - popup: launch getTakeUrl() in a popup
* - modal: launch getTakeUrl() in a modal
* - content: print the value from take() (or do whatever the module wants to
* do)
*/
public function getTakeType() {
return 'content';
}
/**
* Course object entry point for taking. This method should return a value
* corresponding to the type set in getTakeType().
*/
public function take() {
return t('This should be overridden by the module to return course content.');
}
/**
* Return the URL to the course object router.
*
* @return Url
*/
public function getUrl() {
return Url::fromRoute('course.object', [
'course' => $this
->getCourse()
->id(),
'course_object' => $this
->id(),
]);
}
/**
* Get the URL to take this course object, if any.
*
* Outline handlers or subclasses should use getUrl().
*
* @return Url
*/
protected function getTakeUrl() {
}
/**
* Get the URL to edit this course object, if any.
*
* @return Url
*/
public function getEditUrl() {
}
/**
* Get the URL to view this course object, if any.
*
* @return Url
*/
public function getViewUrl() {
}
/**
* Is this course object required for course completion?
*
* @return bool
*/
public function isRequired() {
return (bool) $this
->getOption('required');
}
/**
* If this course object is required, can be it skipped?
*
* @return bool
*/
public function isSkippable() {
return (bool) $this
->getOption('skippable');
}
/**
* Is this object graded?
*
* Returning TRUE here will cause some more configurations to show on the
* object's form.
*
* @return bool
*/
function isGraded() {
return FALSE;
}
/**
* Get the user's status in this course object.
*
* This is how an object would notify the user why they cannot proceed to the
* next step from the course outline. For example, if this was a quiz and
* they failed, this should let them know.
*/
public function getStatus() {
}
/**
* Get a user's fulfillment for this course object. If the user has not
* started this course object, a new, unsaved fulfillment will be return.
*
* @param stdClass $account
* User account to get fulfillment for.
*
* @return CourseObjectFulfillment
*/
public function getFulfillment(AccountInterface $account) {
$entities = \Drupal::entityTypeManager()
->getStorage('course_object_fulfillment')
->loadByProperties([
'coid' => $this
->id(),
'uid' => $account
->id(),
]);
if ($entities) {
return reset($entities);
}
else {
return CourseObjectFulfillment::create(array(
'coid' => $this
->id(),
'uid' => $account
->id(),
'object_type' => $this
->get('object_type')
->getString(),
));
}
}
/**
* Get the instance ID. This could be the external component ID, a Node ID...
*
* @return string
*/
function getInstanceId() {
return $this
->getOption('instance');
}
/**
* Set this object's instance ID.
*
* @param string $id The external ID of this course object.
*/
function setInstanceId($id) {
return $this
->setOption('instance', $id);
}
/**
* Set the Course for this CourseObject.
*
* @param Course|int $course
* A Course or node ID.
*
* @return CourseObject
*/
public function setCourse($course) {
if (is_numeric($course)) {
$this
->setOption('cid', $course);
}
else {
$this
->setOption('cid', $course
->id());
}
return $this;
}
/**
* Get the Course that contains this CourseObject.
*
* @return Course
*/
function getCourse() {
return Course::load($this
->get('cid')
->getString());
}
/**
* Get the object component title for this course object.
*
* @return string
*/
function getComponentName() {
$handlers = course_get_handlers('object');
return $handlers[$this
->getComponent()]['label'];
}
/**
* Get the object component for this course object.
*
* @return string
*/
function getComponent() {
return $this
->getOption('object_type');
}
/**
* Set the object component for this course object.
*
* @param string $component
* The object's component.
*
* @return CourseObject
*/
function setComponent($component) {
return $this
->setOption('object_type', $component);
}
/**
* Set the internal course object ID.
*
* @param int $coid
* ID of the course object.
*/
function setId($coid) {
return $this
->setOption('coid', $coid);
}
/**
* Creates a course object.
*
* For example, this would create the new node and return the node ID if this
* was a CourseObjectNode.
*
* Do not confuse this with save(), which saves the course outline record for
* tracking.
*
* Course objects should call setInstanceId() if this is a course object
* that creates external resources.
*/
public function createInstance() {
//$this->setInstanceId($id);
}
/**
* Objects should implement this method if they need to delete their own
* content.
*/
public function deleteInstance() {
//thing_delete();
}
function getTitle() {
$object_info = course_get_handlers('object');
// If title is not specified, set title from component.
if (!$this
->getOption('title')) {
// Get the component name from object info.
$title = $object_info[$this
->getOption('object_type')]['label'];
$this
->setOption('title', $title);
}
return $this
->getOption('title');
}
/**
* Give the course object a chance do asynchronous polling and set completion
* on demand.
*
* Useful for external objects.
*/
function poll() {
}
/**
* Let the course object provide its own reports.
*
* @return array
* An array indexed by report key, containing 'title' which is the menu link
* in the course object reports.
*/
function getReports() {
return array(
'default' => array(
'title' => 'Overview',
),
);
}
/**
* Let the course object provide its own reports.
*
* @return array
* An array containing:
* - title: The title of this report as show on the page
* - content: Content to be displayed.
* - url: URL to be loaded in an iframe.
* Reports should return either 'content' or 'url'.
*/
function getReport($key) {
if ($key == 'default') {
return array(
'title' => 'Overview',
'content' => views_embed_view('course_object_report', 'default', $this
->getCourse()
->id(), $this
->getId()),
);
}
}
function freeze() {
}
function thaw($ice) {
}
/**
* Returns an translated error message if this object has issues with cloning.
*
* @return mixed
* TRUE if cloning is supported, FALSE if cloning is not supported. A string
* if the object can clone but with caveats.
*/
function getCloneAbility() {
return FALSE;
}
/**
* {@inheritdoc}
*
* Apply configuration from session and let objects create their instances
* before saving the course object.
*/
public function save() {
// If there is no title, set it.
$this
->getTitle();
if ($ice = $this
->getOption('freeze')) {
// Found frozen data. Restore it to this object.
$this
->setInstanceId($this
->thaw($ice));
$this
->setOption('freeze', NULL);
}
// Pull temporary configuration from session.
foreach ($this
->optionsDefinition() as $key => $default) {
$value = $this
->getOption($key);
$this
->set($key, $value);
}
// If there is no instance ID, tell the object to create external content.
if (!$this
->getInstanceId()) {
$this
->createInstance();
}
// Set the ID to NULL because this is a temporary course object being
// created for the first time.
if (strpos($this
->getId(), 'course_object_') !== FALSE) {
$this
->setId(NULL);
}
$data = $this
->get('data')
->getValue();
// Delegate to parent entity save.
return parent::save();
}
/**
* Checks the temporary status of a course object.
*/
function isTemporary() {
return strpos($this
->getId(), 'course_object_') === 0;
}
/**
* Return the number of occurances that can be in a course at the same time.
* For example, the design of the Certificate module can only have 1 set of
* mappings per node. The same goes for Course Credit. We may also want a
* course object that can only be added twice (for example, a before/after
* comparison).
*
* This method is static because we might have to call it without an object
* being instantiated.
*/
public static function getMaxOccurences() {
return FALSE;
}
/**
* Set the context of which course this course object belongs to.
*
* The return parameters should be compliant with course_determine_context().
*/
public static function context() {
}
/**
* Generate URI from course object.
*/
public function uri() {
return array(
'path' => 'node/' . $this->nid . '/object/' . $this
->identifier(),
);
}
/**
* {@inheritdoc}
*/
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
$fields = parent::baseFieldDefinitions($entity_type);
$fields['cid'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Course'));
$fields['object_type'] = BaseFieldDefinition::create('string')
->setLabel(t('Object'));
$fields['title'] = BaseFieldDefinition::create('string')
->setDisplayConfigurable('view', TRUE)
->setLabel(t('Object title'));
$fields['enabled'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Course ID'));
$fields['instance'] = BaseFieldDefinition::create('string')
->setLabel(t('Instance identifier'))
->setDescription('An ID used to identify a remote activity.');
$fields['required'] = BaseFieldDefinition::create('boolean')
->setDisplayConfigurable('view', TRUE)
->setLabel(t('Required'));
$fields['weight'] = BaseFieldDefinition::create('integer')
->setLabel(t('Weight'));
$fields['hidden'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Hidden'));
$fields['duration'] = BaseFieldDefinition::create('integer')
->setLabel(t('Duration'));
$fields['data'] = BaseFieldDefinition::create('map')
->setLabel(t('Data'));
$fields['created'] = BaseFieldDefinition::create('created')
->setRevisionable(TRUE)
->setLabel('Created');
$fields['changed'] = BaseFieldDefinition::create('changed')
->setRevisionable(TRUE)
->setLabel('Changed');
return $fields;
}
/**
* Set field in extra data if needed.
*
* {@inheritdoc}
*/
function set($name, $value, $notify = TRUE) {
if (!in_array($name, array_keys($this
->getFieldDefinitions()))) {
$extra = parent::get('data')
->getValue() ?? [];
$extra[0][$name] = $value;
return parent::set('data', $extra[0]);
}
else {
return parent::set($name, $value, $notify);
}
}
/**
* Map this object base to the base entity class.
*/
public function getEntityType() {
$entityType = parent::getEntityType();
$class = get_class($this);
$entityType
->set('originalClass', $class);
return $entityType;
}
public static function postDelete(Drupal\Core\Entity\EntityStorageInterface $storage, array $entities) {
$fs = \Drupal::entityTypeManager()
->getStorage('course_object_fulfillment');
$coids = array_keys($entities);
$fulfillments = $fs
->loadByProperties([
'coid' => $coids,
]);
$fs
->delete($fulfillments);
parent::postDelete($storage, $entities);
}
/**
* Clear static access cache on save.
*
* {@inheritdoc}
*/
public function postSave(Drupal\Core\Entity\EntityStorageInterface $storage, $update = TRUE) {
parent::postSave($storage, $update);
\Drupal::entityTypeManager()
->getAccessControlHandler('course_object')
->resetCache();
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
CacheableDependencyTrait:: |
protected | property | Cache contexts. | |
CacheableDependencyTrait:: |
protected | property | Cache max-age. | |
CacheableDependencyTrait:: |
protected | property | Cache tags. | |
CacheableDependencyTrait:: |
protected | function | Sets cacheability; useful for value object constructors. | |
ContentEntityBase:: |
protected | property | Language code identifying the entity active language. | |
ContentEntityBase:: |
protected | property | Local cache for the default language code. | |
ContentEntityBase:: |
protected | property | The default langcode entity key. | |
ContentEntityBase:: |
protected | property | Whether the revision translation affected flag has been enforced. | |
ContentEntityBase:: |
protected | property | Holds untranslatable entity keys such as the ID, bundle, and revision ID. | |
ContentEntityBase:: |
protected | property | Local cache for field definitions. | |
ContentEntityBase:: |
protected | property | The array of fields, each being an instance of FieldItemListInterface. | |
ContentEntityBase:: |
protected static | property | Local cache for fields to skip from the checking for translation changes. | |
ContentEntityBase:: |
protected | property | Indicates whether this is the default revision. | |
ContentEntityBase:: |
protected | property | The language entity key. | |
ContentEntityBase:: |
protected | property | Local cache for the available language objects. | |
ContentEntityBase:: |
protected | property | The loaded revision ID before the new revision was set. | |
ContentEntityBase:: |
protected | property | Boolean indicating whether a new revision should be created on save. | |
ContentEntityBase:: |
protected | property | The revision translation affected entity key. | |
ContentEntityBase:: |
protected | property | Holds translatable entity keys such as the label. | |
ContentEntityBase:: |
protected | property | A flag indicating whether a translation object is being initialized. | |
ContentEntityBase:: |
protected | property | An array of entity translation metadata. | |
ContentEntityBase:: |
protected | property | Whether entity validation was performed. | |
ContentEntityBase:: |
protected | property | Whether entity validation is required before saving the entity. | |
ContentEntityBase:: |
protected | property | The plain data values of the contained fields. | |
ContentEntityBase:: |
public | function |
Checks data value access. Overrides EntityBase:: |
1 |
ContentEntityBase:: |
public | function |
Adds a new translation to the translatable object. Overrides TranslatableInterface:: |
|
ContentEntityBase:: |
public | function |
Gets the bundle of the entity. Overrides EntityBase:: |
|
ContentEntityBase:: |
public static | function |
Provides field definitions for a specific bundle. Overrides FieldableEntityInterface:: |
4 |
ContentEntityBase:: |
protected | function | Clear entity translation object cache to remove stale references. | |
ContentEntityBase:: |
public | function |
Creates a duplicate of the entity. Overrides EntityBase:: |
1 |
ContentEntityBase:: |
public | function |
Gets a field item list. Overrides FieldableEntityInterface:: |
|
ContentEntityBase:: |
protected | function | Gets the value of the given entity key, if defined. | 1 |
ContentEntityBase:: |
public | function |
Gets the definition of a contained field. Overrides FieldableEntityInterface:: |
|
ContentEntityBase:: |
public | function |
Gets an array of field definitions of all contained fields. Overrides FieldableEntityInterface:: |
|
ContentEntityBase:: |
public | function |
Gets an array of all field item lists. Overrides FieldableEntityInterface:: |
|
ContentEntityBase:: |
protected | function | Returns an array of field names to skip in ::hasTranslationChanges. | 1 |
ContentEntityBase:: |
public | function | ||
ContentEntityBase:: |
protected | function | ||
ContentEntityBase:: |
public | function |
Gets the loaded Revision ID of the entity. Overrides RevisionableInterface:: |
|
ContentEntityBase:: |
public | function |
Gets the revision identifier of the entity. Overrides RevisionableInterface:: |
|
ContentEntityBase:: |
public | function |
Gets an array of field item lists for translatable fields. Overrides FieldableEntityInterface:: |
|
ContentEntityBase:: |
protected | function | Gets a translated field. | |
ContentEntityBase:: |
public | function |
Gets a translation of the data. Overrides TranslatableInterface:: |
|
ContentEntityBase:: |
public | function |
Returns the languages the data is translated to. Overrides TranslatableInterface:: |
|
ContentEntityBase:: |
public | function |
Returns the translation status. Overrides TranslationStatusInterface:: |
|
ContentEntityBase:: |
public | function |
Returns the translatable object referring to the original language. Overrides TranslatableInterface:: |
|
ContentEntityBase:: |
public | function |
Determines whether the entity has a field with the given name. Overrides FieldableEntityInterface:: |
|
ContentEntityBase:: |
public | function |
Checks there is a translation for the given language code. Overrides TranslatableInterface:: |
|
ContentEntityBase:: |
public | function |
Determines if the current translation of the entity has unsaved changes. Overrides TranslatableInterface:: |
|
ContentEntityBase:: |
public | function |
Gets the identifier. Overrides EntityBase:: |
|
ContentEntityBase:: |
protected | function | Instantiates a translation object for an existing translation. | |
ContentEntityBase:: |
public | function |
Checks if this entity is the default revision. Overrides RevisionableInterface:: |
|
ContentEntityBase:: |
public | function |
Checks whether the translation is the default one. Overrides TranslatableInterface:: |
|
ContentEntityBase:: |
public | function |
Checks if untranslatable fields should affect only the default translation. Overrides TranslatableRevisionableInterface:: |
|
ContentEntityBase:: |
public | function |
Checks if this entity is the latest revision. Overrides RevisionableInterface:: |
|
ContentEntityBase:: |
public | function |
Checks whether this is the latest revision affecting this translation. Overrides TranslatableRevisionableInterface:: |
|
ContentEntityBase:: |
public | function |
Determines whether a new revision should be created on save. Overrides RevisionableInterface:: |
|
ContentEntityBase:: |
public | function |
Checks whether the translation is new. Overrides TranslatableInterface:: |
|
ContentEntityBase:: |
public | function |
Checks whether the current translation is affected by the current revision. Overrides TranslatableRevisionableInterface:: |
|
ContentEntityBase:: |
public | function |
Checks if the revision translation affected flag value has been enforced. Overrides TranslatableRevisionableInterface:: |
|
ContentEntityBase:: |
public | function |
Returns the translation support status. Overrides TranslatableInterface:: |
|
ContentEntityBase:: |
public | function |
Checks whether entity validation is required before saving the entity. Overrides FieldableEntityInterface:: |
|
ContentEntityBase:: |
public | function |
Gets the label of the entity. Overrides EntityBase:: |
2 |
ContentEntityBase:: |
public | function |
Gets the language of the entity. Overrides EntityBase:: |
|
ContentEntityBase:: |
public | function |
Reacts to changes to a field. Overrides FieldableEntityInterface:: |
|
ContentEntityBase:: |
public | function |
Acts on a created entity before hooks are invoked. Overrides EntityBase:: |
|
ContentEntityBase:: |
public | function |
Acts on an entity before the presave hook is invoked. Overrides EntityBase:: |
5 |
ContentEntityBase:: |
public | function |
Acts on a revision before it gets saved. Overrides RevisionableInterface:: |
2 |
ContentEntityBase:: |
public | function |
Gets a list of entities referenced by this entity. Overrides EntityBase:: |
1 |
ContentEntityBase:: |
public | function |
Removes the translation identified by the given language code. Overrides TranslatableInterface:: |
|
ContentEntityBase:: |
protected | function | Populates the local cache for the default language code. | |
ContentEntityBase:: |
public | function |
Enforces an entity to be saved as a new revision. Overrides RevisionableInterface:: |
|
ContentEntityBase:: |
public | function |
Marks the current revision translation as affected. Overrides TranslatableRevisionableInterface:: |
|
ContentEntityBase:: |
public | function |
Enforces the revision translation affected flag value. Overrides TranslatableRevisionableInterface:: |
|
ContentEntityBase:: |
public | function |
Sets whether entity validation is required before saving the entity. Overrides FieldableEntityInterface:: |
|
ContentEntityBase:: |
public | function |
Gets an array of all property values. Overrides EntityBase:: |
|
ContentEntityBase:: |
protected | function | Updates language for already instantiated fields. | |
ContentEntityBase:: |
public | function |
Updates the loaded Revision ID with the revision ID. Overrides RevisionableInterface:: |
|
ContentEntityBase:: |
public | function | Updates the original values with the interim changes. | |
ContentEntityBase:: |
public | function |
Gets the entity UUID (Universally Unique Identifier). Overrides EntityBase:: |
|
ContentEntityBase:: |
public | function |
Validates the currently set values. Overrides FieldableEntityInterface:: |
|
ContentEntityBase:: |
public | function |
Checks whether the entity object was a default revision when it was saved. Overrides RevisionableInterface:: |
|
ContentEntityBase:: |
public | function | Magic method: Implements a deep clone. | |
ContentEntityBase:: |
public | function |
Constructs an Entity object. Overrides EntityBase:: |
|
ContentEntityBase:: |
public | function | Implements the magic method for getting object properties. | |
ContentEntityBase:: |
public | function | Implements the magic method for isset(). | |
ContentEntityBase:: |
public | function | Implements the magic method for setting object properties. | |
ContentEntityBase:: |
public | function |
Overrides EntityBase:: |
|
ContentEntityBase:: |
public | function | Implements the magic method for unset(). | |
CourseHandler:: |
final public | function | Merge an array of options onto the existing options. | |
CourseHandler:: |
public | function | Get an array of access messages. | |
CourseHandler:: |
function | Handlers must have an ID. | ||
CourseHandler:: |
public | function | Get an handler option's value. | |
CourseHandler:: |
public | function | Return a list of warning strings about this handler. | 3 |
CourseHandler:: |
private | function | Merge arrays with replace, not append. | |
CourseHandler:: |
public | function | Set an access message to be displayed along with the course object when it is in the outline. For example, "This activity will open on XYZ" or "Please complete Step 1 to take this activity." | |
CourseHandler:: |
public | function | Set an option for this handler. | |
CourseHandler:: |
final public | function | Set this entire handler's options. | |
CourseObject:: |
protected | property | ||
CourseObject:: |
public static | function |
Provides base field definitions for an entity type. Overrides ContentEntityBase:: |
|
CourseObject:: |
public static | function | Set the context of which course this course object belongs to. | 3 |
CourseObject:: |
public | function | Creates a course object. | 3 |
CourseObject:: |
public | function | Objects should implement this method if they need to delete their own content. | 1 |
CourseObject:: |
function | 1 | ||
CourseObject:: |
function | Returns an translated error message if this object has issues with cloning. | 4 | |
CourseObject:: |
function | Get the object component for this course object. | ||
CourseObject:: |
function | Get the object component title for this course object. | ||
CourseObject:: |
function | Get the Course that contains this CourseObject. | ||
CourseObject:: |
public | function | Get the URL to edit this course object, if any. | 1 |
CourseObject:: |
public | function |
Map this object base to the base entity class. Overrides EntityBase:: |
|
CourseObject:: |
public | function | Get a user's fulfillment for this course object. If the user has not started this course object, a new, unsaved fulfillment will be return. | |
CourseObject:: |
function | Get the instance ID. This could be the external component ID, a Node ID... | ||
CourseObject:: |
public static | function | Return the number of occurances that can be in a course at the same time. For example, the design of the Certificate module can only have 1 set of mappings per node. The same goes for Course Credit. We may also want a course object that can only be… | 2 |
CourseObject:: |
public | function |
Get options, with session options, except weight, having precedence. Overrides CourseHandler:: |
|
CourseObject:: |
public | function |
Get core options summary. Overrides CourseHandler:: |
3 |
CourseObject:: |
function | Let the course object provide its own reports. | 2 | |
CourseObject:: |
function | Let the course object provide its own reports. | 2 | |
CourseObject:: |
public | function | Get the user's status in this course object. | 2 |
CourseObject:: |
public | function | How should this course object be executed? | 4 |
CourseObject:: |
protected | function | Get the URL to take this course object, if any. | 3 |
CourseObject:: |
function | 1 | ||
CourseObject:: |
public | function | Return the URL to the course object router. | |
CourseObject:: |
public | function | Get the URL to view this course object, if any. | 1 |
CourseObject:: |
public | function | Specify whether fulfillment uses asynchronous polling. | |
CourseObject:: |
public | function | ||
CourseObject:: |
function | Is this object graded? | 2 | |
CourseObject:: |
public | function | Is this course object required for course completion? | |
CourseObject:: |
public | function | If this course object is required, can be it skipped? | |
CourseObject:: |
function | Checks the temporary status of a course object. | ||
CourseObject:: |
private | function | ||
CourseObject:: |
public | function |
Define configuration elements and their defaults. Overrides CourseHandler:: |
5 |
CourseObject:: |
public | function |
Default options form for all course objects. Overrides CourseHandler:: |
5 |
CourseObject:: |
public | function |
Save object configs to cache. Overrides CourseHandler:: |
1 |
CourseObject:: |
public | function |
Validate? Overrides CourseHandler:: |
1 |
CourseObject:: |
public | function | Override navigation links. | 1 |
CourseObject:: |
public | function | Overrides a course outline list item. | 1 |
CourseObject:: |
function | Give the course object a chance do asynchronous polling and set completion on demand. | ||
CourseObject:: |
public static | function |
Acts on deleted entities before the delete hook is invoked. Overrides EntityBase:: |
|
CourseObject:: |
public | function |
Clear static access cache on save. Overrides ContentEntityBase:: |
1 |
CourseObject:: |
public | function | Get all course object implementations of getOptionsSummary(). | |
CourseObject:: |
public | function |
Apply configuration from session and let objects create their instances
before saving the course object. Overrides EntityBase:: |
1 |
CourseObject:: |
function |
Set field in extra data if needed. Overrides ContentEntityBase:: |
||
CourseObject:: |
function | Set the object component for this course object. | ||
CourseObject:: |
public | function | Set the Course for this CourseObject. | |
CourseObject:: |
public | function | Mark this object for deletion. | |
CourseObject:: |
function | Set the internal course object ID. | ||
CourseObject:: |
function | Set this object's instance ID. | ||
CourseObject:: |
public | function | Course object entry point for taking. This method should return a value corresponding to the type set in getTakeType(). | 4 |
CourseObject:: |
final public | function | Take a course object. | |
CourseObject:: |
function | 1 | ||
CourseObject:: |
public | function | Generate URI from course object. | |
DependencySerializationTrait:: |
protected | property | An array of entity type IDs keyed by the property name of their storages. | |
DependencySerializationTrait:: |
protected | property | An array of service IDs keyed by property name used for serialization. | |
DependencySerializationTrait:: |
public | function | Aliased as: traitSleep | 1 |
DependencySerializationTrait:: |
public | function | 2 | |
EntityBase:: |
protected | property | Boolean indicating whether the entity should be forced to be new. | |
EntityBase:: |
protected | property | The entity type. | |
EntityBase:: |
protected | property | A typed data object wrapping this entity. | |
EntityBase:: |
public static | function |
Constructs a new entity object, without permanently saving it. Overrides EntityInterface:: |
|
EntityBase:: |
public | function |
Deletes an entity permanently. Overrides EntityInterface:: |
2 |
EntityBase:: |
public | function |
Enforces an entity to be new. Overrides EntityInterface:: |
|
EntityBase:: |
protected | function | Gets the entity manager. | |
EntityBase:: |
protected | function | Gets the entity type bundle info service. | |
EntityBase:: |
protected | function | Gets the entity type manager. | |
EntityBase:: |
public | function |
The cache contexts associated with this object. Overrides CacheableDependencyTrait:: |
|
EntityBase:: |
public | function |
The maximum age for which this object may be cached. Overrides CacheableDependencyTrait:: |
|
EntityBase:: |
public | function |
The cache tags associated with this object. Overrides CacheableDependencyTrait:: |
|
EntityBase:: |
public | function |
Returns the cache tags that should be used to invalidate caches. Overrides EntityInterface:: |
2 |
EntityBase:: |
public | function |
Gets the key that is used to store configuration dependencies. Overrides EntityInterface:: |
|
EntityBase:: |
public | function |
Gets the configuration dependency name. Overrides EntityInterface:: |
1 |
EntityBase:: |
public | function |
Gets the configuration target identifier for the entity. Overrides EntityInterface:: |
1 |
EntityBase:: |
public | function |
Gets the ID of the type of the entity. Overrides EntityInterface:: |
|
EntityBase:: |
protected | function | The list cache tags to invalidate for this entity. | |
EntityBase:: |
public | function |
Gets the original ID. Overrides EntityInterface:: |
1 |
EntityBase:: |
public | function |
Gets a typed data object for this entity object. Overrides EntityInterface:: |
|
EntityBase:: |
public | function |
Indicates if a link template exists for a given key. Overrides EntityInterface:: |
|
EntityBase:: |
protected static | function | Invalidates an entity's cache tags upon delete. | 1 |
EntityBase:: |
protected | function | Invalidates an entity's cache tags upon save. | 1 |
EntityBase:: |
public | function |
Determines whether the entity is new. Overrides EntityInterface:: |
2 |
EntityBase:: |
protected | function | Gets the language manager. | |
EntityBase:: |
public | function |
Deprecated way of generating a link to the entity. See toLink(). Overrides EntityInterface:: |
1 |
EntityBase:: |
protected | function | Gets an array link templates. | 1 |
EntityBase:: |
public static | function |
Loads an entity. Overrides EntityInterface:: |
|
EntityBase:: |
public static | function |
Loads one or more entities. Overrides EntityInterface:: |
|
EntityBase:: |
public static | function |
Acts on loaded entities. Overrides EntityInterface:: |
2 |
EntityBase:: |
public static | function |
Changes the values of an entity before it is created. Overrides EntityInterface:: |
5 |
EntityBase:: |
public static | function |
Acts on entities before they are deleted and before hooks are invoked. Overrides EntityInterface:: |
4 |
EntityBase:: |
public | function |
Sets the original ID. Overrides EntityInterface:: |
1 |
EntityBase:: |
public | function |
Generates the HTML for a link to this entity. Overrides EntityInterface:: |
|
EntityBase:: |
public | function |
Gets the URL object for the entity. Overrides EntityInterface:: |
2 |
EntityBase:: |
public | function |
Gets a list of URI relationships supported by this entity. Overrides EntityInterface:: |
|
EntityBase:: |
public | function |
Gets the public URL for this entity. Overrides EntityInterface:: |
2 |
EntityBase:: |
public | function |
Gets the URL object for the entity. Overrides EntityInterface:: |
1 |
EntityBase:: |
protected | function | Gets an array of placeholders for this entity. | 2 |
EntityBase:: |
protected | function | Gets the UUID generator. | |
EntityChangesDetectionTrait:: |
protected | function | Returns an array of field names to skip when checking for changes. Aliased as: traitGetFieldsToSkipFromTranslationChangesCheck | |
RefinableCacheableDependencyTrait:: |
public | function | 1 | |
RefinableCacheableDependencyTrait:: |
public | function | ||
RefinableCacheableDependencyTrait:: |
public | function | ||
RefinableCacheableDependencyTrait:: |
public | function | ||
SynchronizableEntityTrait:: |
protected | property | Whether this entity is being created, updated or deleted through a synchronization process. | |
SynchronizableEntityTrait:: |
public | function | ||
SynchronizableEntityTrait:: |
public | function | ||
TranslationStatusInterface:: |
constant | Status code identifying a newly created translation. | ||
TranslationStatusInterface:: |
constant | Status code identifying an existing translation. | ||
TranslationStatusInterface:: |
constant | Status code identifying a removed translation. |