event_platform-1.0.x-dev/event_platform_scheduler/src/Controller/Scheduler.php

event_platform_scheduler/src/Controller/Scheduler.php
<?php

namespace Drupal\event_platform_scheduler\Controller;

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\AlertCommand;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\event_platform_scheduler\SchedulerTrait;
use Drupal\smart_date\SmartDateManager;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides listings of instances (with overrides) for a specified rule.
 */
class Scheduler extends ControllerBase {

  use SchedulerTrait;

  /**
   * An array of the rooms that are defined.
   *
   * @var array
   */
  protected $rooms;

  /**
   * An array of the time slots available.
   *
   * @var array
   */
  protected $timeSlots;

  /**
   * Smart Date service manager.
   *
   * @var \Drupal\smart_date\SmartDateManager
   */
  protected $smartDateManager;

  /**
   * The configuration factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * {@inheritdoc}
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, SmartDateManager $smart_date_manager, ConfigFactoryInterface $config_factory) {
    $this->entityTypeManager = $entity_type_manager;
    $this->smartDateManager = $smart_date_manager;
    $this->configFactory = $config_factory;
  }

  /**
   * {@inheritdoc}
   *
   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
   *   The Drupal service container.
   *
   * @return static
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager'),
      $container->get('smart_date.manager'),
      $container->get('config.factory'),
    );
  }

  /**
   * Generate the grid used to assign times and rooms to sessions.
   *
   * @return array
   *   Render array of the grid and sessions.
   */
  public function schedulerInterface() {
    $storage = $this->entityTypeManager->getStorage('taxonomy_term');

    $rooms = $storage->loadByProperties([
      'vid' => 'room',
    ]);
    $this->rooms = $rooms;

    $time_slots = $storage->loadByProperties([
      'vid' => 'time_slot',
    ]);
    $this->timeSlots = $time_slots;

    $output['wrapper'] = [
      '#type' => 'container',
      '#attributes' => [
        'id' => 'scheduler--wrapper',
      ],
    ];
    $output['wrapper']['table'] = $this->buildSlotsTable();
    if ($sessions_output = $this->listSessions()) {
      $heading = [
        '#type' => 'html_tag',
        '#tag' => 'h3',
        '#value' => $this->t('Sessions'),
      ];
      $unassign = [
        '#type' => 'html_tag',
        '#tag' => 'p',
        '#value' => $this->t('Unassign'),
        '#attributes' => [
          'class' => ['scheduler--unassign', 'hidden'],
        ],
      ];
      $output['wrapper']['sessions'] = [
        '#type' => 'container',
        '#attributes' => [
          'id' => 'scheduler--sessions',
        ],
      ];
      $output['wrapper']['sessions']['list'] = [
        'heading' => $heading,
        'unassign' => $unassign,
        'output' => $sessions_output,
      ];

    }

    return $output;
  }

  /**
   * Use helper functions to generate a table of available slots.
   *
   * @return array
   *   Render array of the table of available slots.
   */
  public function buildSlotsTable() {
    $header = $this->buildHeader();
    $rows = $this->buildRows();
    $build['table'] = [
      '#type' => 'table',
      '#attributes' => [
        'id' => 'scheduler-table',
      ],
      '#header' => $header,
      '#rows' => $rows,
      '#empty' => $this
        ->t('There are no @label yet. Use the <a href="@time-slots-tool">Time Slots</a> tool to generate your event\'s time slots in bulk.', [
          '@label' => 'time slots',
          '@time-slots-tool' => '/admin/event-details/scheduler/time_slots',
        ]),
    ];
    $build['table']['#attached']['library'][] = 'event_platform_scheduler/scheduler';

    return $build;

  }

  /**
   * Builds the header row for the listing.
   *
   * @return array
   *   A render array structure of header strings.
   */
  private function buildHeader() {
    $row['label'] = $this->t('Time Slots');
    $row['dummy'] = '';
    foreach ($this->rooms as $room) {
      $row['room' . $room->id()] = $room->label();
    }
    return $row;
  }

  /**
   * Generate the rows for the grid based on the rooms and time slots.
   *
   * @return array
   *   Render array of the grid rows.
   */
  private function buildRows() {
    $rows = [];
    $last_row_date = '';
    $date_row_num = NULL;
    foreach ($this->timeSlots as $time_slot) {
      $row = [];
      // Use the Smart Date service to format dates and times.
      if (!is_array($date_values_array = $time_slot->get('field_when')->getValue())) {
        continue;
      }
      $date_values = array_pop($date_values_array);
      $row_date = $this->smartDateManager->formatSmartDate($date_values['value'], $date_values['end_value'], 'date_only', NULL, 'string');
      // Avoid outputting the same date repeatedly.
      if ($row_date == $last_row_date) {
        $rows[$date_row_num]['date']['rowspan'] += 1;
      }
      else {
        $row['date'] = [
          'data' => $row_date,
          'rowspan' => 1,
        ];
        $date_row_num = $time_slot->id();
        $last_row_date = $row_date;
      }
      // Use Smart Date's time only format to provide a concise time column.
      $row['time'] = $this->smartDateManager->formatSmartDate($date_values['value'], $date_values['end_value'], 'time_only', NULL, 'string');
      // Generate a drag target slot for each room in this time slot.
      foreach ($this->rooms as $room) {
        $row[] = [
          'data' => '',
          'class' => 'empty',
          'data-room' => $room->id(),
          'data-timeslot' => $time_slot->id(),
        ];
      }
      $rows[$time_slot->id()] = $row;
    }
    return $rows;
  }

  /**
   * Generate a list of the sessions available.
   *
   * @return array
   *   Render array of the sessions available.
   */
  private function listSessions() {
    // Add the filters key first so they'll be above the sessions.
    $output = [
      'filters' => [],
    ];
    $config = $this->configFactory->get('event_platform_scheduler.settings');
    $types = $config->get('types');
    $states = $config->get('states');
    $filter_fields = $config->get('filters');
    $filter_field_labels = [];
    $filter_field_values = [];
    $filters = [];
    // If more than one type specified, provide a type filter.
    if ($types && is_array($types) && count($types) > 1) {
      $type_objects = $this->entityTypeManager
        ->getStorage('node_type')
        ->loadMultiple($types);
      $type_labels = [
        '' => $this->t('- Any -'),
      ];
      foreach ($type_objects as $type_id => $type_object) {
        $type_labels[$type_id] = $type_object->label();
      }
      $filters['type'] = [
        '#type' => 'select',
        '#name' => 'type',
        '#title' => 'Content Type',
        '#options' => $type_labels,
      ];
    }

    // @todo restrict this to accepted sessions?
    $storage = $this->entityTypeManager->getStorage('node');
    if ($filter_fields) {
      $taxonomy_storage = $this->entityTypeManager->getStorage('taxonomy_term');
    }
    // If no states specified, pull all content of the chosen types.
    if (empty($states)) {
      $sessions = $storage->loadByProperties([
        'type' => $types,
      ]);
    }
    else {
      // Create an array to track unmoderated chosen types.
      $types_to_process = $types;
      $sessions = [];
      $chosen_states = [];
      foreach ($states as $state_hash) {
        $parts = explode($this->separator, $state_hash, 2);
        $workflow = $parts[0];
        $state = $parts[1] ?? '';
        if (!$state) {
          continue;
        }
        $chosen_states[$workflow][] = $state;
      }
      $workflows_to_process = $this->getWorkflowsForTypes($types);
      foreach ($workflows_to_process as $workflow => $chosen_types) {
        $types_to_process = array_diff($types_to_process, $chosen_types);
        if (empty($chosen_states[$workflow])) {
          continue;
        }
        $query = $storage->getQuery()
          ->addTag('moderation_state')
          ->accessCheck(TRUE)
          ->condition('type', $chosen_types, 'IN')
          ->addMetaData('states', $chosen_states[$workflow]);
        $wf_sessions = $query->execute();
        if ($wf_sessions) {
          $sessions = array_merge($sessions, $wf_sessions);
        }
      }
      if ($types_to_process) {
        $query = $storage->getQuery()
          ->accessCheck(TRUE)
          ->condition('type', $types_to_process, 'IN');
        $wf_sessions = $query->execute();
        if ($wf_sessions) {
          $sessions = array_merge($sessions, $wf_sessions);
        }
      }
    }
    if ($sessions) {
      foreach ($sessions as $session_id) {
        $session = $storage->load($session_id);
        // @todo show list of presenters if set.
        $user_storage = $this->entityTypeManager->getStorage('user');
        $user = $user_storage->load($session->get('uid')->getString());
        $label = $this->t('@title by @presenters', [
          '@title' => $session->label(),
          '@presenters' => $user->label(),
        ]);
        // Only pass room and timeslot if both are populated.
        $room = $session->get('field_r')->getString();
        $timeslot = $session->get('field_time_slot')->getString();
        if ($room xor $timeslot) {
          $room = '';
          $timeslot = '';
        }
        $output['sessions'][$session->id()] = [
          '#type' => 'html_tag',
          '#tag' => 'p',
          '#value' => $label,
          '#attributes' => [
            'class' => ['session'],
            'draggable' => 'true',
            'id' => 'node-' . $session->id(),
            'data-nid' => $session->id(),
            'data-room' => $room,
            'data-timeslot' => $timeslot,
            'data-type' => $session->bundle(),
            'data-user' => $session->get('uid')->getString(),
          ],
        ];
        // Generate any appropriate filter values.
        if ($filter_fields && is_array($filter_fields)) {
          foreach ($filter_fields as $field) {
            if (!$session->hasField($field)) {
              continue;
            }
            $value = $session->get($field)->getString();
            if (!$value) {
              continue;
            }
            // Add the data attribute.
            $output['sessions'][$session->id()]['#attributes']['data-' . $field] = $value;
            // If about to add the first value for a field, add an empty value.
            if (!isset($filter_field_values[$field])) {
              $filter_field_values[$field] = [
                '' => $this->t('- Any -'),
              ];
            }
            // Add the value and the taxonomy term name.
            $filter_field_values[$field][$value] = $taxonomy_storage->load($value)->label();
            // Use the session object to get the field label if necessary.
            if (!isset($filter_field_labels[$field])) {
              $filter_field_labels[$field] = $session->$field?->getFieldDefinition()->getLabel();
            }
          }
        }
      }
    }
    // Create the filter dropdowns.
    if ($filter_field_labels) {
      foreach ($filter_field_labels as $field => $filter_field_label) {
        $filters[$field] = [
          '#type' => 'select',
          '#name' => $field,
          '#title' => $filter_field_label,
          '#options' => $filter_field_values[$field],
        ];
      }
    }
    // Enclose the filters in a details element.
    if ($filters) {
      $output['filters'] = [
        '#type' => 'details',
        '#id' => 'scheduler_filters',
        '#title' => $this->t('Filters'),
        'fields' => $filters,
      ];
    }
    else {
      unset($output['filters']);
    }

    return $output;
  }

  /**
   * AJAX endpoint to assign a room and time slot to a session.
   *
   * @param object $node
   *   Upcasted node object.
   * @param int $rid
   *   Term id of the room to assign.
   * @param int $tid
   *   Term id of the time slot to assign.
   *
   * @return object
   *   AJAX response.
   */
  public function assign($node, $rid, $tid) {
    // Do stuff.
    $node->set('field_r', $rid);
    $node->set('field_time_slot', $tid);
    $node->save();
    $response = new AjaxResponse();
    $text = $this->t('The @type node is updated.', ['@type' => $node->bundle()]);
    $response->addCommand(new AlertCommand($text));
    return $response;
  }

  /**
   * AJAX callback to reset the room and time slots for a session.
   *
   * @param object $node
   *   Upcasted node object.
   *
   * @return object
   *   AJAX response.
   */
  public function unassign($node) {
    // Do stuff.
    $node->set('field_r', NULL);
    $node->set('field_time_slot', NULL);
    $node->save();
    $response = new AjaxResponse();
    return $response;
  }

}

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

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