You are here

function office_hours_field_formatter_view in Office Hours 7

Implements hook_field_formatter_view().

Be careful: date_api uses PHP: 0=Sunday, and DateObject uses ISO: 1=Sunday.

File

includes/office_hours.formatter.inc, line 240
Implements the office_hours formatter.

Code

function office_hours_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  if (!$items) {
    return $element;
  }

  // Allow other modules to alter the items before the calculations are done.
  // @see office_hours.api.php for an example.
  $context = array(
    'entity_type' => $entity_type,
    'entity' => $entity,
    'field' => $field,
    'instance' => $instance,
    'langcode' => $langcode,
    'display' => $display,
  );
  drupal_alter('office_hours_field_formatter_view', $items, $context);

  // Initialize formatter settings.
  $settings = _office_hours_field_formatter_defaults($display['settings']);

  // Initialize daynames, using date_api as key: 0=Sun - 6=Sat.
  switch ($settings['daysformat']) {
    case 'number':

      // ISO-8601 numerical representation.
      $daynames = range(1, 7);
      break;
    case 'none':
      $daynames = array_fill(0, 7, '');
      break;
    case 'long':
      $daynames = date_week_days(TRUE);
      break;
    case 'short':
    default:
      $daynames = date_week_days_abbr(TRUE, TRUE, 3);
      break;
  }

  // Initialize days and times, using date_api as key (0=Sun, 6-Sat)
  // Empty days are not yet present in $items, and are now added in $days.
  $days = array();
  for ($day = 0; $day < 7; $day++) {
    $days[$day] = array(
      'startday' => $day,
      'endday' => NULL,
      'times' => NULL,
      'current' => FALSE,
      'next' => FALSE,
    );
  }

  // @TODO: support timezones.
  $timezone = NULL;

  // Avoid repetitive calculations, use static.
  // See http://drupal.org/node/1969956.
  // And even better, avoid the expensive DateObject.
  $today = (int) idate('w', $_SERVER['REQUEST_TIME']);

  // Get daynumber sun=0 - sat=6.
  $now = date('Gi', $_SERVER['REQUEST_TIME']);

  // 'Gi' format.
  $next = NULL;

  // Loop through all lines. Detect the current line and the open/closed status.
  // Convert the daynumber to (int) to get '0' for Sundays, not 'false'.
  foreach (element_children($items) as $key => $arraykey) {
    $el = $items[$arraykey];

    // Calculate start and end times.
    $day = $el['day'];
    $start = _office_hours_time_to_mil($el['starthours']);

    // 'Gi' format.
    $end = _office_hours_time_to_mil($el['endhours']);

    // 'Gi' format.
    $comment = $el['comment'];
    $times = array(
      'start' => $start,
      'end' => $end,
      'comment' => $comment,
    );
    $days[$day]['times'][] = $times;

    // Are we currently open? If not, when is the next time?
    // Remember: empty days are not in $items; they are present in $days.
    // Note: the 'open' determination is moved to file office_hours.formatter.inc.
    if ($day < $today) {

      // Initialize to first day of (next) week, in case we're closed
      // the rest of the week.
      if ($next === NULL) {
        $next = (int) $day;
      }
    }
    if ($day - $today == -1 || $day - $today == 6) {

      // We were open yesterday evening, check if we are still open.
      if ($start >= $end && $end >= $now) {
        $days[$day]['current'] = TRUE;
        $next = (int) $day;
      }
    }
    elseif ($day == $today) {
      if ($start <= $now) {

        // We were open today, check if we are still open.
        if ($start > $end || $start == $end || $start < $end && $end > $now) {

          // We have closed already.
          $days[$day]['current'] = TRUE;
          $next = (int) $day;
        }
        else {

          // We have already closed.
        }
      }
      else {

        // We will open later today.
        $next = (int) $day;
      }
    }
    elseif ($day > $today) {
      if ($next === NULL || $next < $today) {
        $next = (int) $day;
      }
    }
  }
  if ($next !== NULL) {
    $days[(int) $next]['next'] = TRUE;
  }

  // We have to separate display from JS 'Open' calculation here.
  // So we copy the days array before it get modified for display:
  // See https://www.drupal.org/project/office_hours/issues/2919519
  $days2calc = $days;

  // Reorder weekdays to match the first day of the week, using formatter settings;
  // $days = date_week_days_ordered($days);  //using variable_get('date_first_day');
  if ($settings['date_first_day'] > 0) {
    for ($i = 1; $i <= $settings['date_first_day']; $i++) {
      $last = array_shift($days);
      array_push($days, $last);
    }
  }

  // Check if we're compressing times. If so, combine lines of the same day into one.
  if ($settings['compress']) {
    foreach ($days as $day => &$info) {
      if (is_array($info['times'])) {

        // Initialize first block of the day.
        $day_times = $info['times'][0];

        // Compress other block in first block.
        foreach ($info['times'] as $index => $block_times) {
          $day_times['start'] = min($day_times['start'], $block_times['start']);
          $day_times['end'] = max($day_times['end'], $block_times['end']);
        }
        $info['times'] = array(
          0 => $day_times,
        );
      }
    }
  }

  // Check if we're grouping days.
  if ($settings['grouped']) {
    for ($i = 0; $i < 7; $i++) {
      if ($i == 0) {
        $times = $days[$i]['times'];
      }
      elseif ($times != $days[$i]['times']) {
        $times = $days[$i]['times'];
      }
      else {

        // N.B. for 0=Sundays, we need to (int) the indices.
        $days[$i]['endday'] = $days[(int) $i]['startday'];
        $days[$i]['startday'] = $days[(int) $i - 1]['startday'];
        $days[$i]['current'] = $days[(int) $i]['current'] || $days[(int) $i - 1]['current'];
        $days[$i]['next'] = $days[(int) $i]['next'] || $days[(int) $i - 1]['next'];
        unset($days[(int) $i - 1]);
      }
    }
  }

  // Theme the result.
  $element[] = array(
    '#markup' => theme('office_hours_field_formatter_default', array(
      'element' => $items,
      'display' => $display,
      'days' => $days,
      'days2calc' => $days2calc,
      'settings' => $settings,
      'daynames' => $daynames,
      'timezone' => $timezone,
      'context' => array(
        'entity_type' => $entity_type,
        'entity' => $entity,
        'field' => $field,
        'instance' => $instance,
        'langcode' => $langcode,
        'items' => $items,
        'display' => $display,
      ),
    )),
    '#attached' => array(
      'js' => array(
        drupal_get_path('module', 'office_hours') . '/js/office_hours.formatter.js',
      ),
    ),
  );
  return $element;
}