You are here

public function Calendar::render in Calendar 8.2

Same name and namespace in other branches
  1. 8 src/Plugin/views/style/Calendar.php \Drupal\calendar\Plugin\views\style\Calendar::render()

Render the display in this style.

Overrides StylePluginBase::render

File

src/Plugin/views/style/Calendar.php, line 435

Class

Calendar
Views style plugin for the Calendar module.

Namespace

Drupal\calendar\Plugin\views\style

Code

public function render() {
  $field_argument = NULL;
  if (empty($this->view->argument)) {
    return [];
  }

  // Add calendar style information to the view.
  $this->styleInfo
    ->setGranularity($this->options['granularity']);
  $this->styleInfo
    ->setCalendarPopup($this->displayHandler
    ->getOption('calendar_popup'));
  $this->styleInfo
    ->setDayNameSize($this->options['day_name_size']);
  $this->styleInfo
    ->setMini($this->options['mini']);
  $this->styleInfo
    ->setShowWeekNumbers($this->options['with_weekno']);
  $this->styleInfo
    ->setColorField($this->options['colors']);
  $this->styleInfo
    ->setWeekLink($this->options['granularity_links']['week']);
  $this->styleInfo
    ->setDayLink($this->options['granularity_links']['day']);
  $this->styleInfo
    ->setMultiAllDayStyle($this->options['multi_allday_style']);
  $this->styleInfo
    ->setMultiAllDayTitle($this->options['multi_allday_title']);
  $this->styleInfo
    ->setmultiAllDayViewMode($this->options['multi_allday_viewmode']);
  $calendar_arguments = $this->calendarHelper
    ->getCalendarArguments($this->view);
  $field_argument = $calendar_arguments[0]['field'];

  // Calculate offset for all dates from timezone set for current user.
  // Because Drupal 8 requires PHP >= 7.1 we can use DateTime functions.
  // @TODO find out if there is a need for storing offset in CalendarEvent.
  $current_user = \Drupal::entityTypeManager()
    ->getStorage('user')
    ->load($this->account
    ->id());
  if (!empty($current_user->timezone->value)) {
    $tz_user = new \DateTimeZone($current_user->timezone->value);
    $storagetime = new \DateTime('now', new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE));
    $tz_interval = \DateInterval::createFromDateString($tz_user
      ->getOffset($storagetime) . 'seconds');
  }
  else {
    $tz_interval = \DateInterval::createFromDateString('0 seconds');
  }
  $granularity = $this->styleInfo
    ->getGranularity();
  $color_field = $ref = NULL;
  $color_info = explode('.', $this->styleInfo
    ->getColorField());
  if (count($color_info) > 1) {
    $entity_type = $color_info[0];
    $color_field = $color_info[1];

    // Check if color_field is some field from base entity.
    if (isset($this->view->result[0]->_entity) && $this->view->result[0]->_entity
      ->getEntityTypeId() !== $entity_type) {

      // Color_field may be part of some reference
      foreach ($this->view->relationship as $field_name => $field) {

        // Tricky! Index entity type uses space, not underscore.
        if (isset($field->definition['entity type']) && $field->definition['entity type'] === $entity_type) {
          $ref = $field_name;
        }
        elseif ($entity_type === 'group' && isset($color_field)) {
          $ref = 'gid';
        }
      }
    }
  }
  $caldays = $this->calendarHelper
    ->{$granularity}($this->view);
  if (in_array($granularity, [
    'week',
    'day',
  ])) {
    foreach ($caldays as $weekno => $data) {
      foreach ($data['weekdays'] as $date => $day) {
        if (is_numeric($date)) {
          $caldays[$weekno]['weekdays'][(string) $date]['other'] = $this->calendarHelper
            ->buildDayHours();
        }
      }
    }
  }

  // Build links to displays with other granularities.
  foreach ($caldays as $weekno => $weekday) {

    // If enabled from StyleInfo set links.
    $year = $month = $week = $day_route = $week_route = NULL;
    $year = $caldays[$weekno]['startweekdate']
      ->format('Y');
    $month = $caldays[$weekno]['startweekdate']
      ->format('m');
    $week = $weekno;
    if (isset($this->options['granularity_links']['week'])) {
      $week_route = $this->options['granularity_links']['week'];
    }
    if (isset($this->options['granularity_links']['day'])) {
      $day_route = $this->options['granularity_links']['day'];
    }
    if ($this->styleInfo
      ->getShowWeekNumbers() === '1') {
      $show_week = true;
    }
    else {
      $show_week = NULL;
    }
    $caldays[$weekno]['linkdata'] = [
      'year' => $year,
      'month' => $month,
      'week' => $week,
      'show_week' => $show_week,
      'week_route' => $week_route,
      'day_route' => $day_route,
    ];
  }

  // Loop over view result rows and create Events.
  $events = [];
  foreach ($this->view->result as $row) {

    // Fields can be multivalue.
    foreach ($row->_entity
      ->get($field_argument) as $delta => $item) {
      $event = NULL;
      if (isset($item->end_value) && isset($item->value)) {
        $enddate = new DrupalDateTime($item->end_value);
        $startdate = new DrupalDateTime($item->value);

        // Check if enddate is after start of week AND begindate before end of week.
        // This is dependant on user timezone as this may split events over day borders.
        $event = new CalendarEvent();
        $event
          ->setId($row->_entity
          ->id());

        //          $event->setLabel($row->_entity->get('title')->value);
        $event
          ->setWeekno($this->calendarHelper::weekInfoDate($startdate)['weekno']);
        $event
          ->setEndDate($enddate
          ->add($tz_interval));
        $event
          ->setStartDate($startdate
          ->add($tz_interval));

        // @TODO set weekno before adding tz_interval?
        $event
          ->setWeekno($this->calendarHelper::weekInfoDate($startdate)['weekno']);
        if ($color_field) {
          if ($ref && isset($row->_relationship_entities[$ref]->{$color_field}->color)) {
            $event
              ->setColor($row->_relationship_entities[$ref]->{$color_field}->color);
          }
          elseif (isset($row->_entity->{$color_field}->color)) {
            $event
              ->setColor($row->_entity->{$color_field}->color);
          }
        }

        // @TODO fix rendering of row through Plugin (expecting array, string provided).
        $event
          ->setRow($this->view->rowPlugin
          ->render($row));
        if ($event
          ->getStartDate()
          ->format('Ymd') === $event
          ->getEndDate()
          ->format('Ymd')) {
          $event
            ->setMultiDay(FALSE);

          // To find alldays we ignore seconds.
          if ($event
            ->getStartDate()
            ->format('Hi') === '0000' && $event
            ->getEndDate()
            ->format('Hi') === '2359') {
            $event
              ->setAllDay(TRUE);
            $event
              ->setLabel(self::renderTitle($row->_entity));
          }
          else {
            $event
              ->setAllDay(FALSE);
            $event
              ->setLength($enddate
              ->diff($startdate));
          }
        }
        else {
          $event
            ->setMultiDay(TRUE);
          $event
            ->setLabel(self::renderTitle($row->_entity));
          $event
            ->setAllDay(FALSE);
        }
      }
      elseif ($item->value) {
        $event = new CalendarEvent();
        $event
          ->setId($row->_entity
          ->id());
        $startdate = new DrupalDateTime($item->value);
        $event
          ->setStartDate($startdate
          ->add($tz_interval));
        $event
          ->setWeekno($this->calendarHelper::weekInfoDate($startdate)['weekno']);
        $event
          ->setMultiDay(FALSE);
        $event
          ->setAllDay(FALSE);
        $event
          ->setLabel($row->_entity
          ->get('title')->value);

        // @TODO fix rendering of row through Plugin (expecting array, string provided).
        $event
          ->setRow($this->view->rowPlugin
          ->render($row));
      }
    }
    $events[] = $event;
    if ($event
      ->getMultiDay()) {
      $offset = $this->calendarHelper::weekInfoDate($event
        ->getStartDate())['startweekdate']
        ->diff($event
        ->getStartDate());
      $event
        ->setOffSet($offset);
      $diff = $event
        ->getStartDate()
        ->diff($event
        ->getEndDate());
      if ($diff->d < 7 - $offset->d) {
        $length = $event
          ->getStartDate()
          ->diff($event
          ->getEndDate());
      }
      elseif ($event
        ->getOffSet()->d > 0 || $event
        ->getOffSet()->h > 0) {

        //              if ($event->getOffSet()->h > 0) {
        //                $days = 'P' . (7 - 1 - $event->getOffSet()->d) . 'D';
        //              }
        //              else {
        $days = 'P' . (7 - $event
          ->getOffSet()->d) . 'D';

        //              }
        $length = new \DateInterval($days);
      }
      else {
        $length = new \DateInterval('P7D');
      }
      $event
        ->setLength($length);

      // Multidate events may lie outside of range so we need to clone them.
      if ($diff->d > $length->d) {
        $year = $event
          ->getStartDate()
          ->format('Y');
        $weekno = $event
          ->getWeekno();
        $max = $weekno + (int) floor($diff->d / 7);
        do {
          $weekno++;
          $week_start = $this->calendarHelper::weekInfo($year . $weekno)['startweekdate'];
          $c_event = clone $event;
          $c_event
            ->setStartDate($week_start);
          $c_event
            ->setWeekno($weekno);
          $c_event
            ->setOffset(new \DateInterval('P0D'));

          // Substract first day since diff for length is measured in extra days.
          $c_diff = $week_start
            ->diff($event
            ->getEndDate());
          if ($c_diff->d > 7) {
            $c_event
              ->setLength(new \DateInterval('P7D'));
          }
          else {
            $c_event
              ->setLength($c_diff);
          }
          $events[] = $c_event;
        } while ($weekno < $max);
      }
    }
  }

  // Add events to caldays array if they lie within caldays range.
  foreach ($events as $event) {
    if (isset($caldays[$event
      ->getWeekno()])) {
      if ($event
        ->getMultiDay()) {
        $caldays[$event
          ->getWeekno()]['weekdays'][$event
          ->getStartDate()
          ->format('Ymd')]['multiday'][$event
          ->getId()] = $event;
      }
      elseif ($event
        ->getAllDay()) {
        $caldays[$event
          ->getWeekno()]['weekdays'][$event
          ->getStartDate()
          ->format('Ymd')]['allday'][$event
          ->getId()] = $event;
      }
      else {
        if (in_array($granularity, [
          'week',
          'day',
        ])) {

          // Check if time for startdate is present, otherwise round to nearest time.
          if (array_key_exists($event
            ->getStartDate()
            ->format('H.i'), array_keys($caldays[$event
            ->getWeekno()]['weekdays'][$event
            ->getStartDate()
            ->format('Ymd')]['other']))) {
            $caldays[$event
              ->getWeekno()]['weekdays'][$event
              ->getStartDate()
              ->format('Ymd')]['other'][$event
              ->getStartDate()
              ->format('H.i')][$event
              ->getId()] = $event;
          }
          else {
            $nearest = $event
              ->getStartDate()
              ->format('H') . '.00';
            $caldays[$event
              ->getWeekno()]['weekdays'][$event
              ->getStartDate()
              ->format('Ymd')]['other'][$nearest][$event
              ->getId()] = $event;
          }
        }
        else {
          $caldays[$event
            ->getWeekno()]['weekdays'][$event
            ->getStartDate()
            ->format('Ymd')]['other'][$event
            ->getId()] = $event;
        }
      }
    }
  }

  // Derive template to use.
  $template = 'calendar_' . $this->styleInfo
    ->getGranularity();
  if ($this->view->styleInfo
    ->getMini()) {
    $template = 'calendar_mini_' . $this->styleInfo
      ->getGranularity();
  }
  $build = [
    '#theme' => $template,
    '#view' => $this->view,
    '#options' => $this->options,
    '#rows' => $caldays,
  ];
  return $build;
}