You are here

office_hours.module in Office Hours 6.2

Creates a field and widget for inserting working or office hours per day

File

office_hours.module
View source
<?php

/**
 * @file
 * Creates a field and widget for inserting working or office hours per day
 */

/**
 * Implementation of hook_theme().
 */
function office_hours_theme() {
  return array(
    'office_hours_formatter_default' => array(
      'arguments' => array(
        'element' => NULL,
      ),
      'file' => 'office_hours.theme.inc',
    ),
    'office_hours' => array(
      'arguments' => array(
        'element' => NULL,
      ),
      'file' => 'office_hours.theme.inc',
    ),
    'office_hours_multiple_values' => array(
      'arguments' => array(
        'element' => NULL,
      ),
      'file' => 'office_hours.theme.inc',
    ),
    'office_hours_select' => array(
      'arguments' => array(
        'element' => NULL,
      ),
      'file' => 'office_hours.theme.inc',
    ),
  );
}

/**
 * Implementation of hook_form_alter().
 */
function office_hours_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'content_field_edit_form') {
    if ($form['#field']['type'] == 'office_hours') {
      $description = t('14 hours blocks is the current default. see below for limiting it');
      $description .= '<br/><strong>' . t('Warning! Changing this setting after data has been created could result in the loss of data!') . '</strong>';
      $form['field']['multiple'] = array(
        '#type' => 'select',
        '#title' => t('Number of values'),
        '#options' => drupal_map_assoc(array(
          14,
        )),
        '#default_value' => 14,
        '#description' => $description,
      );
    }
  }
  if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] . '_node_form' == $form_id) {
    $type = content_types($form['#node']->type);
    foreach ($type['fields'] as $field) {
      if ($field['type'] == 'office_hours') {
        $form[$field['field_name']]['#theme'] = 'office_hours_multiple_values';
      }
    }
  }
}

/**
 * Implementation of hook_init().
 */
function office_hours_init() {
  drupal_add_css(drupal_get_path('module', 'office_hours') . '/office_hours.css');

  //drupal_add_js(drupal_get_path('module', 'office_hours') .'/office_hours.js','theme');
}

/**
 * Implementation of hook_content_is_empty().
 */
function office_hours_content_is_empty($item, $field) {
  if ($item['starthours'] == '' || $item['endhours'] == '' || !isset($item['day'])) {
    return TRUE;
  }
  return FALSE;
}

/**
 * Implementation of hook_field_info().
 *
 * @return
 *   An array keyed by field type name. Each element of the array is an associative
 *   array with these keys and values:
 *   - "label": The human-readable label for the field type.
 */
function office_hours_field_info() {
  return array(
    'office_hours' => array(
      'label' => 'Office Hours',
      'description' => t('Store office or opening hours in the database.'),
      'callbacks' => array(
        'tables' => CONTENT_CALLBACK_DEFAULT,
        'arguments' => CONTENT_CALLBACK_DEFAULT,
      ),
    ),
  );
}

/**
 * Implementation of hook_field_settings().
 *
 * Handle the parameters for a field.
 */
function office_hours_field_settings($op, $field) {
  switch ($op) {
    case 'form':

      //$options = _office_hours_create_hours_arr($field, FALSE);
      $form = array();
      $form['hoursformat'] = array(
        '#type' => 'select',
        '#title' => t('Hours format'),
        '#options' => array(
          t('24 hrs.'),
          t('12 hrs'),
        ),
        '#default_value' => $field['hoursformat'] ? $field['hoursformat'] : 0,
        '#required' => FALSE,
        '#description' => t('Format of the clock. IMPORTANT NOTE: if you do not select "Multiple values", you can enter only one day.'),
      );
      $form['granularity'] = array(
        '#type' => 'select',
        '#title' => t('granularity of time'),
        '#options' => array(
          '60' => t('Hours'),
          '30' => t('Half hours'),
          '15' => t('Quarter hours'),
        ),
        '#default_value' => $field['granularity'] ? $field['granularity'] : 0,
        '#required' => FALSE,
        '#description' => t('Allow inserting quarter hours, half hours, or only hours of the day'),
      );
      $form['limitstart'] = array(
        '#type' => 'office_hours_select',
        '#title' => t('Limit widget start hours'),
        '#default_value' => '',
        //$field['limitstart']? $field['limitstart'] : '',
        '#granularity' => $field['granularity'],
        '#hoursformat' => $field['hoursformat'],
        '#prefix' => '<div class="office-hours-block" style="display:inline">',
      );
      $form['limitend'] = array(
        '#type' => 'office_hours_select',
        '#title' => t('Limit widget end hours'),
        '#default_hours' => '',
        //$field['limitend']? $field['limitend'] : '',
        '#granularity' => $field['granularity'],
        '#hoursformat' => $field['hoursformat'],
        '#suffix' => '</div>',
      );
      $form['valhrs'] = array(
        '#type' => 'checkbox',
        '#title' => t('Validate hours'),
        '#required' => FALSE,
        '#default_value' => isset($field['valhrs']) ? $field['valhrs'] : 0,
        '#description' => t('Please note that this will work as long as the opening hours are not through midnight.'),
      );
      $form['addhrs'] = array(
        '#type' => 'checkbox',
        '#title' => t('Display the "Add more hours" link'),
        '#required' => FALSE,
        '#default_value' => isset($field['addhrs']) ? $field['addhrs'] : 1,
        '#description' => t('Make it possible to use 2 hour block for each day instead of one'),
      );
      return $form;
    case 'validate':

      /* if ( $field['limitend'] <= $field['limitstart'] && $field['limitend'] != 'none'  && $field['limitstart'] !='none') {
             form_set_error('limitend','Limit ending hours are earlier than start hours');
         }*/
      break;
    case 'save':
      return array(
        'hoursformat',
        'granularity',
        'limitstart',
        'limitend',
        'valhrs',
        'addhrs',
      );
    case 'database columns':
      $columns = array(
        'day' => array(
          'type' => 'int',
          'not null' => FALSE,
          'sortable' => TRUE,
        ),
        'starthours' => array(
          'type' => 'int',
          'not null' => FALSE,
          'sortable' => TRUE,
        ),
        'endhours' => array(
          'type' => 'int',
          'not null' => FALSE,
          'sortable' => TRUE,
        ),
      );
      return $columns;
      break;
    case 'views data':
      $data = _office_hours_views_field_views_data($field);
      $db_info = content_database_info($field);
      $table_alias = content_views_tablename($field);

      // Swap the filter handler.
      $data[$table_alias][$field['field_name'] . '_day']['filter']['handler'] = 'office_hours_handler_filter_day';
      $data[$table_alias][$field['field_name'] . '_starthours']['filter']['handler'] = 'office_hours_handler_filter_hours';
      $data[$table_alias][$field['field_name'] . '_endhours']['filter']['handler'] = 'content_handler_handler_filter_hours';
      return $data;
      break;
  }
}

/**
 * Implementation of hook_field().
 * 
 */
function office_hours_field($op, &$node, $field, &$items, $teaser, $page) {
  switch ($op) {
    case 'validate':
      foreach ($items as $delta => $item) {
        if ($field['valhrs']) {
          if (!empty($item['starthours']) && !empty($item['endhours'])) {
            $error_field = $field['field_name'] . '][' . $delta . '][endhours';
            if ($item['starthours'] > $item['endhours']) {
              form_set_error($error_field, t('Closing hours are earlier than opening hours validator'));
            }
          }
        }
      }
      break;
    case 'presave':
      break;
    case 'insert':
    case 'update':
      $items = _office_hours_set_weight($items);
      break;
  }
}

/**
 * Implementation of hook_field_formatter_info().
 */
function office_hours_field_formatter_info() {
  return array(
    'default' => array(
      'label' => 'default',
      'field types' => array(
        'office_hours',
      ),
      'multiple values' => CONTENT_HANDLE_MODULE,
    ),
  );
}

/**
 * Implementation of hook_widget_info().
 */
function office_hours_widget_info() {
  return array(
    'office_hours' => array(
      'label' => t('Office Hours'),
      'field types' => array(
        'office_hours',
      ),
      'multiple values' => CONTENT_HANDLE_CORE,
      'callbacks' => array(
        'default value' => CONTENT_CALLBACK_DEFAULT,
      ),
    ),
  );
}

/**
 * Implementation of FAPI hook_elements().
 */
function office_hours_elements() {
  module_load_include('elements.inc', 'office_hours');
  return _office_hours_elements();
}

/**
 * Implementation of hook_widget().
 */
function office_hours_widget(&$form, &$form_state, $field, $items, $delta = 0) {
  $element = array(
    '#type' => $field['widget']['type'],
    '#default_value' => isset($items[$delta]) ? $items[$delta] : '',
  );
  return $element;
}

/**
 * Implementation of hook_views_api().
 */
function office_hours_views_api() {
  return array(
    'api' => 2,
    'path' => drupal_get_path('module', 'office_hours') . '/includes',
  );
}
function _office_hours_arrange_day($items) {
  $first = variable_get('date_first_day', 0);
  while ($first > 0) {
    $shifted = array_shift($items);
    $items[] = $shifted;
    if (isset($items[13])) {
      $shifted = array_shift($items);
      $items[] = $shifted;
    }
    $first--;
  }
  return $items;
}

/**
 * helper function to create hours array.
 * items are saved in 24 hours string format (i.e '18:00').
 */

/* we're using date_api now
 function _office_hours_create_hours_arr($field = array(), $limit = TRUE) { 
  $ophours['none'] = t('None');
  $start = ($field['limitstart'] != 'none') ? $field['limitstart']: 0;
  $end = ($field['limitend'] != 'none') ?  $field['limitend'] : 2400 ;
  $gran = ($field['granularity'] == 0) ? 60 : $field['granularity'];
  for ($i = $start; $i <= $end; $i+=$gran  ) {
    if (substr($i, -2) == 60) {
      $i += 40;
    }
    $ophours[$i] = ($field['hoursformat']) ? _office_hours_mil_to_tf($i) :  _office_hours_convert_to_ampm($i);
  }
  return $ophours;
}*/

/**
 * Helper function for conversion of clock format.
 */
function _office_hours_convert_to_ampm($hour) {
  if (!strstr($hour, ":")) {
    $hour = _office_hours_mil_to_tf($hour);
  }
  list($hr, $min) = explode(":", $hour);
  if ($hr == '0') {

    // midnight
    $hr = 12;
    $ampm = ' AM';
  }
  elseif ($hr == 12) {

    // noon
    $hr = 12;
    $ampm = ' PM';
  }
  elseif ($hr > 12 && $hr < 24) {

    // a pm time
    $hr = $hr - 12;
    $ampm = ' PM';
  }
  else {
    $ampm = ' AM';
  }
  return $hr . ':' . $min . $ampm;
}
function _office_hours_tf_to_mil($hour) {
  if (strstr($hour, ':') == FALSE || is_null($hour)) {
    return $hour;
  }
  list($hr, $min) = explode(":", $hour);
  $hr = $hr * 60 + $min;
  return $hr;
}
function _office_hours_mil_to_tf($time = '') {
  $hour = substr($time, 0, -2) ? substr($time, 0, -2) : '0';
  $min = substr($time, -2) ? substr($time, -2) : '00';
  return $hour . ":" . $min;
}
function _office_hours_set_weight($items) {
  $sorted = array();
  foreach ($items as $key => $item) {
    if (!is_null($item['day'])) {
      $sortkey = (int) $item['day'];
      if (count($items) == 14) {
        $sortkey = $sortkey * 2;
      }
      if (is_array($sorted[$sortkey])) {
        $sorted[$sortkey + 1] = $item;
      }
      else {
        $sorted[$sortkey] = $item;
      }
    }
  }

  //now fill the empty spaces with null values
  foreach (range(0, count($items) - 1) as $value) {
    if (!is_array($sorted[$value])) {
      $sorted[$value] = array(
        'day' => NULL,
        'starthours' => NULL,
        'endhours' => NULL,
      );
    }
  }
  return $sorted;
}

/**
 * Adding all table field into $data in hook_views_data.
 */
function _office_hours_views_field_views_data($field) {
  $field_types = _content_field_types();
  $db_info = content_database_info($field);

  // Field modules that do not store data in the database
  // should not create views data tables.
  if (empty($db_info['columns'])) {
    return;
  }
  $table_alias = content_views_tablename($field);
  $types = array();
  foreach (content_types() as $type) {
    if (isset($type['fields'][$field['field_name']])) {
      $types[] = $type['name'];
    }
  }
  $data = array();
  $data['table']['group'] = t('Content');
  $data['table']['join']['node'] = array(
    'table' => $db_info['table'],
    'left_field' => 'vid',
    'field' => 'vid',
  );
  $columns = array();
  $arguments = array();
  $filters = array();
  foreach ($db_info['columns'] as $column => $attributes) {
    $columns[] = $attributes['column'];
    $sorts[] = !empty($attributes['sortable']) ? TRUE : FALSE;

    // Identify likely filters and arguments for each column based on field type.
    switch ($attributes['type']) {
      case 'int':
      case 'mediumint':
      case 'tinyint':
      case 'bigint':
      case 'serial':
        $filters[] = 'content_handler_filter_numeric';
        $arguments[] = 'content_handler_argument_numeric';
        break;
      case 'numeric':
      case 'float':
        $filters[] = class_exists('views_handler_filter_float') ? 'content_handler_filter_float' : 'content_handler_filter_numeric';
        $arguments[] = 'content_handler_argument_numeric';
        break;
      case 'text':
      case 'blob':

      // TODO add markup handlers for these types
      default:
        $filters[] = 'content_handler_filter_string';
        $arguments[] = 'content_handler_argument_string';
        break;
    }
  }
  $i = 0;

  // Ensure all columns are retrieved,
  $additional_fields = drupal_map_assoc($columns);
  foreach ($columns as $key => $column) {
    list(, , $field_type) = explode('_', $column);
    $data[$column] = array(
      'group' => t('Content'),
      'title' => t($field_types[$field['type']]['label']) . ': ' . t($field['widget']['label']) . ' (' . $field['field_name'] . ' ' . $field_type . ')',
      'help' => t($field_types[$field['type']]['label']) . ' - ' . t('Appears in: @types', array(
        '@types' => implode(', ', $types),
      )),
      'field' => array(
        'field' => $column,
        'table' => $db_info['table'],
        'handler' => 'content_handler_field_multiple',
        'click sortable' => $sorts[$i],
        // 'additional fields' => $additional_fields,
        'content_field_name' => $field['field_name'],
        'allow empty' => TRUE,
        // Access control modules should implement content_views_access_callback().
        'access callback' => 'content_views_access_callback',
        'access arguments' => array(
          $field,
        ),
      ),
      'argument' => array(
        'field' => $column,
        'table' => $db_info['table'],
        'handler' => $arguments[$i],
        'click sortable' => $sorts[$i],
        // TODO used in once place in node.views.inc, should we use it here?
        'name field' => '',
        // TODO

        //'additional fields' => $additional_fields,
        'content_field_name' => $field['field_name'],
        'empty field name' => t('<No value>'),
        'allow empty' => TRUE,
      ),
      'filter' => array(
        'field' => $column,
        'title' => t($field['widget']['label']) . ': ' . $field_type,
        'table' => $db_info['table'],
        'handler' => $filters[$i],
        //'additional fields' => $additional_fields,
        'content_field_name' => $field['field_name'],
        'allow empty' => TRUE,
      ),
    );
    $i++;
  }

  // TODO do we need different handling for sorts with Views 2,
  // especially when relationships are involved?
  if (!empty($sorts[$i])) {
    $data[$column]['sort'] = array(
      'field' => $column,
      'table' => $db_info['table'],
      'handler' => 'content_handler_sort',
      // 'additional fields' => $additional_fields,
      'content_field_name' => $field['field_name'],
      'allow empty' => TRUE,
    );
  }

  // TODO: provide automatic filters, sorts, and arguments for each column, not just the first?
  return array(
    $table_alias => $data,
  );
}

Functions

Namesort descending Description
office_hours_content_is_empty Implementation of hook_content_is_empty().
office_hours_elements Implementation of FAPI hook_elements().
office_hours_field Implementation of hook_field().
office_hours_field_formatter_info Implementation of hook_field_formatter_info().
office_hours_field_info Implementation of hook_field_info().
office_hours_field_settings Implementation of hook_field_settings().
office_hours_form_alter Implementation of hook_form_alter().
office_hours_init Implementation of hook_init().
office_hours_theme Implementation of hook_theme().
office_hours_views_api Implementation of hook_views_api().
office_hours_widget Implementation of hook_widget().
office_hours_widget_info Implementation of hook_widget_info().
_office_hours_arrange_day
_office_hours_convert_to_ampm Helper function for conversion of clock format.
_office_hours_mil_to_tf
_office_hours_set_weight
_office_hours_tf_to_mil
_office_hours_views_field_views_data Adding all table field into $data in hook_views_data.