View source
<?php
namespace Drupal\course_content\Course\Object;
use Drupal\node\Entity\Node;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\GeneratedLink;
use Drupal\Component\Serialization\Json;
use Drupal;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\course\Entity\CourseObject;
use Drupal\node\Entity\NodeType;
use Drupal\node\NodeInterface;
use stdClass;
use function count;
use function course_get_course_object;
use function module_load_include;
use function node_type_get_names;
abstract class CourseObjectNode extends CourseObject {
public static function context() {
$route_match = Drupal::routeMatch();
if ($route_match
->getRouteName() == 'entity.node.canonical') {
$node = $route_match
->getParameter('node');
$type = NodeType::load($node
->bundle());
if ($type
->getThirdPartySetting('course_content', 'use')) {
if ($courseObject = course_get_course_object('content', $node
->id())) {
return array(
'object_type' => 'content',
'instance' => $node
->id(),
);
}
}
$instances = static::getNodeInstances($node);
if (!empty($instances)) {
$node = Node::load($instances[0]);
if ($courseObject = course_get_course_object($node
->bundle(), $node
->id())) {
return array(
'object_type' => $node
->bundle(),
'instance' => $node
->id(),
);
}
}
}
}
public static function getNodeInstances($node) {
return array();
}
public function hasNodePrivacySupport() {
return Drupal::moduleHandler()
->moduleExists('content_access') && Drupal::moduleHandler()
->moduleExists('acl');
}
public abstract function getNodeTypes();
public function getTakeType() {
return 'redirect';
}
public function getTakeUrl() {
if ($this
->getNode()) {
return Url::fromRoute('entity.node.canonical', [
'node' => $this
->getNode()
->id(),
]);
}
}
public function getEditUrl() {
if ($this
->getNode()) {
return Url::fromRoute('entity.node.edit_form', [
'node' => $this
->getNode()
->id(),
]);
}
}
public function getViewUrl() {
if ($this
->getNode()) {
return Url::fromRoute('entity.node.canonical', [
'node' => $this
->getNode()
->id(),
]);
}
}
public function createInstance($node = NULL) {
if (!$node) {
$node = Node::create([
'type' => $this
->getOption('node_type'),
]);
}
$node->title = $this
->getTitle();
$node->uid = Drupal::currentUser()
->id();
$node
->save();
$this
->setInstanceId($node
->id());
}
public function deleteInstance() {
$node = Node::load($this
->getInstanceId());
if ($node) {
$node
->delete();
}
}
public function optionsDefinition() {
$defaults = parent::optionsDefinition();
$defaults['private'] = $this
->hasNodePrivacySupport();
$options = array_intersect_key(node_type_get_names(), array_combine($this
->getNodeTypes(), $this
->getNodeTypes()));
$defaults['node_type'] = key($options);
$defaults['use_node_title'] = 0;
$defaults['clone_and_reference'] = 0;
$defaults['use_existing_node'] = 0;
return $defaults;
}
public function optionsForm(&$form, FormStateInterface $form_state) {
parent::optionsForm($form, $form_state);
$form['node'] = array(
'#type' => 'details',
'#title' => t('Content'),
'#description' => 'Settings for course object content.',
'#group' => 'course_tabs',
'#weight' => 2,
);
$config = $this
->getOptions();
$types = array_combine($this
->getNodeTypes(), $this
->getNodeTypes());
$options = array_intersect_key(node_type_get_names(), $types);
$form['node']['use_existing_node'] = array(
'#type' => 'checkbox',
'#title' => t('Use existing content'),
'#default_value' => (bool) $this
->getOption('use_existing_node'),
'#weight' => 1,
'#access' => $this
->isTemporary(),
);
$form['node']['node_type'] = array(
'#title' => t('Create node'),
'#type' => 'select',
'#options' => $options,
'#description' => t('Selecting a node type will automatically create this node and link it to this course object.'),
'#default_value' => $config['node_type'],
'#states' => array(
'visible' => array(
':input[name="use_existing_node"]' => array(
'checked' => FALSE,
),
),
),
'#weight' => 2,
'#access' => $this
->isTemporary(),
);
if (count($options) > 1) {
$form['node']['node_type']['#required'] = TRUE;
}
$form['node']['instance'] = array(
'#title' => t('Existing content'),
'#type' => 'entity_autocomplete',
'#target_type' => 'node',
'#selection_settings' => [
'target_bundles' => $this
->getNodeTypes(),
],
'#description' => t('Use existing content instead of creating a new one.'),
'#default_value' => !empty($this
->getInstanceId()) ? $this
->getNode() : NULL,
'#maxlength' => 255,
'#states' => array(
'visible' => array(
':input[name="use_existing_node"]' => array(
'checked' => TRUE,
),
),
),
'#weight' => 3,
);
if (Drupal::moduleHandler()
->moduleExists('clone') && !$this
->getInstanceId()) {
$form['node']['clone_and_reference'] = array(
'#title' => t('Clone and reference'),
'#type' => 'checkbox',
'#description' => t('This will clone the selected content first.'),
'#default_value' => $config['clone_and_reference'],
'#weight' => 4,
'#states' => array(
'visible' => array(
':input[name="use_existing_node"]' => array(
'checked' => TRUE,
),
),
),
);
}
$form['node']['use_node_title'] = array(
'#type' => 'checkbox',
'#title' => t('Use existing title'),
'#description' => t("Use the referenced content's title as this course object's title."),
'#default_value' => $config['use_node_title'],
'#weight' => 5,
);
$form['node']['private'] = array(
'#title' => t('Private'),
'#description' => $this
->hasNodePrivacySupport() ? t('This content will not be available to users who are not enrolled in this course.') : t('You must enable content_access and acl in order to restrict course content to users who are enrolled in this course.'),
'#type' => 'checkbox',
'#default_value' => $config['private'],
'#disabled' => !$this
->hasNodePrivacySupport(),
'#weight' => 6,
);
$nid = $this
->getInstanceId();
if ($nid) {
$node = Node::load($nid);
$url = Url::fromRoute('entity.node.canonical', [
'node' => $node
->id(),
], array(
'attributes' => array(
'target' => '_blank',
'title' => t('Open in new window'),
),
));
$link = Link::fromTextAndUrl(t("'%title' [node id %nid]", array(
'%title' => $node
->get('title')
->getString(),
'%nid' => $node
->id(),
)), $url)
->toString();
$form['node']['instance']['#description'] = t('Currently set to @link', array(
'@link' => $link,
));
}
}
public function optionsValidate(&$form, FormStateInterface $form_state) {
parent::optionsValidate($form, $form_state);
$nid = $form_state
->getValues()['instance'];
if (empty($nid) && isset($form_state
->getValues()['node_type']) && empty($form_state
->getValues()['node_type'])) {
$form_state
->setErrorByName('node_type', t('Please select a node type.'));
}
if (($form_state
->getValues()['use_existing_node'] || !$this
->isTemporary()) && empty($nid)) {
$form_state
->setErrorByName('instance', t('Please select a node.'));
}
}
public function optionsSubmit(&$form, FormStateInterface $form_state) {
if ($form_state
->getValue('instance')) {
$nid = $form_state
->getValue('instance');
if (!is_numeric($nid)) {
if (preg_match('/^(?:\\s*|(.*) )?\\[\\s*nid\\s*:\\s*(\\d+)\\s*\\]$/', $nid, $matches)) {
$nid = $matches[2];
}
}
if ($nid) {
$form_state
->setValue('instance', $nid);
}
else {
$form_state
->unsetValue('instance');
}
}
parent::optionsSubmit($form, $form_state);
}
function preSave(EntityStorageInterface $storage, $update = TRUE) {
if ($this
->getOption('clone_and_reference')) {
module_load_include('inc', 'clone', 'clone.pages');
$new_nid = clone_node_save($this
->getOption('instance'));
$this
->setInstanceId($new_nid);
$this
->setOption('clone_and_reference', 0);
}
parent::preSave($storage, $update);
}
function postSave(EntityStorageInterface $storage, $update = TRUE) {
$privacy_enabled = $this
->hasNodePrivacySupport() && $this
->getOption('private');
$external_node = $this
->getInstanceId() > 0;
if ($privacy_enabled && $external_node) {
\Drupal::entityTypeManager()
->getAccessControlHandler('node')
->resetCache();
}
parent::postSave($storage, $update);
}
function freeze() {
if ($this
->getInstanceId() != $this
->getCourse()
->getNode()->nid) {
$ice = new stdClass();
$ice->node = $this
->getNode();
return $ice;
}
}
function thaw($ice) {
$node = $ice->node;
unset($node->nid);
unset($node->vid);
$context = array(
'method' => 'save-edit',
);
Drupal::moduleHandler()
->alter('clone_node', $node, $context);
node_save($node);
$this
->setInstanceId($node
->id());
return $this
->getInstanceId();
}
function getCloneAbility() {
return t('%object will be cloned as a node. Results may vary.', array(
'%object' => $this
->getTitle(),
));
}
function getTitle() {
if ($this
->getOption('use_node_title') && $this
->getNode()) {
return $this
->getNode()->title;
}
else {
return parent::getTitle();
}
}
function getNode() {
return Node::load($this
->get('instance')
->getString());
}
function getOptionsSummary() {
$summary = parent::getOptionsSummary();
if (is_a($summary['instance'], GeneratedLink::class)) {
$url = $this
->getEditUrl();
$url
->setOption('query', \Drupal::service('redirect.destination')
->getAsArray());
$url
->setOption('attributes', [
'class' => 'use-ajax',
'data-dialog-type' => 'modal',
'data-dialog-options' => Json::encode([
'width' => 800,
]),
]);
$link = Link::fromTextAndUrl(t('Edit instance'), $url)
->toString();
$summary['instance'] = $link;
}
return $summary;
}
function getWarnings() {
$warnings = parent::getWarnings();
if ($this
->getInstanceId() && !$this
->getNode()) {
$warnings[] = t('The content associated with this object has been deleted.<br/>Saving the course will create new content from the object settings.');
}
return $warnings;
}
function Xaccess($op = 'view', $account = NULL) {
if ($op == 'take' && !$this
->getNode()) {
return FALSE;
}
return parent::access($op, $account);
}
}