learnosity-1.0.x-dev/src/Element/LearnosityActivityEditor.php

src/Element/LearnosityActivityEditor.php
<?php

namespace Drupal\learnosity\Element;

use Drupal\Core\Entity\EntityFormInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element\FormElement;
use Drupal\Core\Render\Markup;

/**
 * Provides a Learnosity authoring item.
 *
 * @FormElement("learnosity_activity_editor")
 */
class LearnosityActivityEditor extends FormElement {

  /**
   * The entity fields to be stored on this form element.
   *
   * @var array
   */
  public static $entityFields = [
    'reference',
    'data',
  ];

  /**
   * {@inheritdoc}
   */
  public function getInfo() {
    $class = get_class($this);
    $info = [
      '#pre_render' => [
        [$class, 'preRenderLearnosityAuthoring'],
      ],
      '#process' => [
        [$class, 'processAuthoringItem'],
      ],
      '#input' => TRUE,
      '#user' => [],
      '#editor' => 'default',
      '#context' => [],
      '#theme' => 'learnosity_activity_editor',
      '#theme_wrappers' => ['form_element'],
    ];
    $info['#element_validate'] = [[$class, 'validateLearnosityAuthoring']];

    return $info;
  }

  /**
   * Process the authoring item element.
   *
   * @param array $element
   *   The form element.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state object.
   * @param array $complete_form
   *   The complete form.
   *
   * @return array
   *   The modified element.
   */
  public static function processAuthoringItem(array &$element, FormStateInterface $form_state, array &$complete_form) {
    // The value callback has populated the #value array.
    $value = !empty($element['#value']) ? $element['#value'] : NULL;

    $element['#tree'] = TRUE;

    // Hide the default input element.
    $element['#attributes']['type'] = 'hidden';

    // This is necessary to make sure we're always saving the right
    // reference.
    // @see learnosity.authorapi.js.
    foreach (self::$entityFields as $field) {
      $element[$field] = [
        '#type' => 'hidden',
        '#value' => $value[$field],
        '#attributes' => ['id' => 'lrn-field--' . $field],
      ];
    }

    // @todo: Move this to the field widget.
    // Fetch the current entity if applicable. This is passed as a argument
    // to the event dispatcher.
    if ($form_state->getFormObject() instanceof EntityFormInterface) {
      $entity = $form_state->getFormObject()->getEntity();
      $element['#context'] += [
        'entity_type' => $entity->getEntityTypeId(),
        'entity_id' => $entity->id(),
        'langcode' => $entity->language()->getId(),
        'editor' => $element['#editor'],
      ];
    }

    return $element;
  }

  /**
   * Pre render callback.
   *
   * The is originally based on the prerender callback defined on the link
   * element.
   *
   * @param array $element
   *   The element.
   *
   * @return array
   *   Element render array.
   */
  public static function preRenderLearnosityAuthoring(array $element) {
    $learnositySdk = \Drupal::service('learnosity.sdk');
    $learnosityApiEventHandler = \Drupal::service('learnosity.api_event_handler');
    $editor = \Drupal::entityTypeManager()->getStorage('learnosity_activity_editor')->load($element['#editor']);

    // Get the current reference for this activity.
    $reference = $element['#value']['reference'];

    // Fetch the editor config.
    $config = $editor->getConfig(TRUE);

    // Attaching the service library to this render element. This will ensure
    // that the proper learnosity api library gets loaded.
    $element['#attached']['library'][] = 'learnosity/api.authorapi';

    // Set current user id and email if none is provided.
    if (empty($element['#user'])) {
      /** @var \Drupal\user\Entity\User $user */
      $user = \Drupal::service('entity_type.manager')->getStorage('user')->load(\Drupal::currentUser()->id());
      $element['#user'] = [
        'id' => $user->id(),
        'email' => $user->getEmail(),
      ];
    }

    // See which features are enabled for this editor.
    $features = $editor->getFeatures();
    $featureManager = \Drupal::service('plugin.manager.learnosity_feature');
    foreach ($features as $name) {
      $feature = $featureManager->createInstance($name);
      $config['dependencies']['question_editor_api']['init_options']['custom_feature_types'][] = $feature->build();

      $attachments = $feature->buildAttachments();
      if (!empty($attachments)) {
        foreach ($attachments as $item) {
          $element['#attached']['library'][] = $item;
        }
      }
    }

    if (!empty($reference) && !empty($element['#user'])) {
      $signed_request = $learnositySdk->init('author', [
        'mode' => 'activity_edit',
        'reference' => $reference,
        'user' => $element['#user'],
        'config' => $config,
      ], $element['#context']);
    }

    if (!empty($signed_request)) {
      // @todo need a better way to handle context.
      // Prepare the context items to be attached.
      // It will only attach scalar values because arrays and objects should not
      // be passed through javascript.
      $context = [];
      foreach ($element['#context'] as $key => $value) {
        if (is_scalar($value)) {
          $context[$key] = $value;
        }
      }

      // Load core learnosity drupal js file and pass signed request.
      $element['#attached']['library'][] = 'learnosity/learnosity';
      $element['#attached']['library'][] = 'learnosity/learnosity.authorapi';
      $element['#attached']['drupalSettings']['learnosity'] = [
        'service' => 'authorapi',
        'signedRequest' => Markup::create($signed_request),
        'events' => $learnosityApiEventHandler->getSubscribedEvents(),
        'context' => $context,
        'editor' => $element['#editor'],
        // This is necessary in order to toggle between default and custom image
        // upload.
        'uploadWidget' => ($editor->getUploadWidget()) ? $editor->getUploadWidget()['plugin'] : '',
      ];

      // Note: learnosity-author id is required by learnosity in order for the
      // experience to load.
      $element['item'] = [
        '#markup' => Markup::create(' <div id="learnosity-author" data-learnosity="true"></div>'),
      ];
    }

    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
    // Process the #default_value property. If no input is provided then it
    // will process any default value. If none, then it will generate one.
    if ($input === FALSE) {
      // If a value is provided for #default_value.
      if (!empty($element['#default_value'])) {
        // Convert the default value into an array for easier processing.
        if (!is_array($element['#default_value'])) {
          $element['#default_value'] = [$element['#default_value']];
        }

        if (!(reset($element['#default_value']) instanceof EntityInterface)) {
          throw new \InvalidArgumentException('The #default_value property has to be an entity object or an array of entity objects.');
        }

        if (isset($element['#default_value'])) {
          $default_value = $element['#default_value'];
          $activity = reset($default_value);
          return  [
            'reference' => $activity->getReference(),
            'data' => urlencode($activity->getData()),
          ];
        }
      }
      // If there is no value provided for #default_value, then generate a
      // new one UUID.
      else {
        $learnositySdk = \Drupal::service('learnosity.sdk');
        return [
          'reference' => $learnositySdk->generateUuid(),
          'data' => NULL,
        ];
      }
    }
    // If an input is provided by the user then it will return that.
    // This could happen if they decide to choose a different activity.
    if ($input !== FALSE) {
      return $input;
    }

  }

  /**
   * Form element validation handler for entity_autocomplete elements.
   */
  public static function validateLearnosityAuthoring(array &$element, FormStateInterface $form_state, array &$complete_form) {
    $value = NULL;

    if (!empty($element['#value'])) {
      $options = $element['#selection_settings'] + [
        'target_type' => $element['#target_type'],
        'handler' => $element['#selection_handler'],
      ];

      /** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface $handler */
      $handler = \Drupal::service('plugin.manager.entity_reference_selection')->getInstance($options);

      // Check to see if an entity exists.
      $exists = \Drupal::service('entity_type.manager')->getStorage($element['#target_type'])->loadByProperties([
        'reference' => $element['#value']['reference'],
      ]);

      // Userialize data and prepare it to be saved.
      $data = [];
      if (!empty($element['#value']['data'])) {
        $data = json_decode(urldecode($element['#value']['data']), TRUE) ?: [];
      }

      if ($exists) {
        foreach ($exists as $entity) {
          // Make sure that data is up-to-date.
          $entity->setData($data);
          $entity->save();
          $value[] = [
            'entity' => $entity,
          ];
        }
      }
      // If it doesn't exist then create it and reset the value.
      else {
        $input_values = [$element['#value']];
        foreach ($input_values as $input) {
          /** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface $handler */
          $entity = $handler->createNewEntity($element['#target_type'], 'learnosity_activity', $input['reference'], $element['#autocreate']['uid']);
          $entity->setData($data);
          $value[] = [
            'entity' => $entity,
          ];
        }
      }
    }

    // Use only the last value if the form element does not support multiple
    // matches.
    if (!empty($value)) {
      $last_value = $value[count($value) - 1];
      $value = isset($last_value['target_id']) ? $last_value['target_id'] : $last_value;
    }

    $form_state->setValueForElement($element, $value);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc