You are here

agenda.module in Agenda 6

Same filename and directory in other branches
  1. 6.2 agenda.module
  2. 7.2 agenda.module
  3. 7 agenda.module

File

agenda.module
View source
<?php

/**
 * The google calendar feed address
 */
define('AGENDA_SOURCEPATTERN', 'http://www.google.com/calendar/feeds/%s/public/full?hl=en&singleevents=true&sortorder=ascending&orderby=starttime&start-min=%s&start-max=%s&max-results=%d&ctz=UTC');

/**
 * Implementation of hook_help().
 */
function agenda_help($path, $arg) {
  $output = '';

  //declare your output variable
  switch ($path) {
    case 'admin/help#agenda':
      $output = '<p>' . t('Displays an agenda of events from a google calendar') . '</p>';
      break;
    case 'admin/settings/agenda/debug':
      $output = '<p>' . t('The agenda block will not show when there are no applicable events to display. If the block is not showing, and you think it should, this page may help you debug the situation.') . '</p>';
      break;
    case 'admin/build/block/agenda':
      $output = '<p>' . t('Allows the creation of an agenda block.') . '</p>';
      break;
  }
  return $output;
}

/**
 * Implementation of hook_menu().
 */
function agenda_menu() {
  $items = array();
  $items['admin/settings/agenda'] = array(
    'title' => 'Agenda',
    'description' => 'Create new and manage existing agenda calendar blocks',
    'page callback' => 'agenda_admin',
    'page arguments' => array(
      'agenda_admin',
    ),
    'access arguments' => array(
      'configure agenda blocks',
    ),
    'file' => 'agenda.admin.php',
  );
  $items['admin/settings/agenda/%/configure'] = array(
    'title' => 'Configure agenda block',
    'type' => MENU_CALLBACK,
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'agenda_admin_configure',
      3,
    ),
    'access arguments' => array(
      'configure agenda blocks',
    ),
    'file' => 'agenda.admin.php',
  );
  $items['admin/settings/agenda/%/delete'] = array(
    'title' => 'Delete agenda block',
    'type' => MENU_CALLBACK,
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'agenda_admin_delete',
      3,
    ),
    'access arguments' => array(
      'configure agenda blocks',
    ),
    'file' => 'agenda.admin.php',
  );
  $items['admin/settings/agenda/%/debug'] = array(
    'title' => 'Test settings',
    'type' => MENU_CALLBACK,
    'page callback' => 'agenda_debug',
    'page arguments' => array(
      3,
    ),
    'access arguments' => array(
      'configure agenda blocks',
    ),
    'file' => 'agenda.admin.php',
  );
  $items['admin/settings/agenda/%/clear'] = array(
    'type' => MENU_CALLBACK,
    'page callback' => 'agenda_clear',
    'page arguments' => array(
      3,
    ),
    'access arguments' => array(
      'configure agenda blocks',
    ),
    'file' => 'agenda.admin.php',
  );
  return $items;
}

/**
 * Implementation of hook_perm().
 */
function agenda_perm() {
  return array(
    'access agenda content',
    'configure agenda blocks',
  );
}

/**
 * Implementation of hook_init().
 *
 * We have to add the CSS to every page otherwise our CSS gets
 * left out with block caching.
 */
function agenda_init() {
  $basepath = drupal_get_path('module', 'agenda');
  drupal_add_css($basepath . '/agenda.css');
  drupal_add_js($basepath . '/agenda.js');
}

/**
 * Implementation of hook_block().
 */
function agenda_block($op = 'list', $delta = 0) {
  switch ($op) {
    case 'list':
      $res = db_query("SELECT bid, value FROM {agenda} WHERE name = 'title'");
      $blocks = array();
      while ($block = db_fetch_object($res)) {
        $blocks[$block->bid] = array(
          'info' => t('Agenda: @title', array(
            '@title' => agenda_variable_get($block->bid, 'title', 'New block'),
          )),
          'cache' => BLOCK_CACHE_GLOBAL,
        );
      }
      return $blocks;
      break;
    case 'view':
      $block = array(
        'subject' => t('Upcoming'),
        'content' => agenda_display_block($delta),
      );
      return $block;
      break;
  }
}

/**
 * Implementation of hook_theme().
 */
function agenda_theme($existing, $type, $theme, $path) {
  $theme = array(
    'agenda_block' => array(
      'arguments' => array(
        'events' => array(),
        'block' => new stdClass(),
      ),
      'template' => 'agenda-block',
    ),
    'agenda_admin' => array(
      'arguments' => array(
        'table' => '',
      ),
      'template' => 'agenda-admin',
    ),
  );
  return $theme;
}

/**
 * Generate the themed agenda block
 *
 * @return string
 */
function agenda_display_block($delta = 0) {

  // Check block exists
  if ($delta === 0 || !($block = agenda_settings($delta))) {
    return false;
  }

  // Group the events by date
  $events = agenda_get_events($block);
  $groupedevents = array();
  foreach ($events as $event) {
    $groupedevents[$event['when']][] = $event;
  }
  ksort($groupedevents);

  // Filter the events based on their date
  $datelimit = $block->datelimit;
  $count = 0;
  $events = array();
  foreach ($groupedevents as $date => $eventdata) {
    if ($count >= $datelimit) {
      break;
    }
    $events[$date] = $eventdata;
    $count++;
  }

  // Render
  if (count($events)) {
    $output = theme('agenda_block', $events, $block);
  }
  elseif (empty($block->noeventstext)) {
    $output = NULL;
  }
  else {
    $output = filter_xss($block->noeventstext);
  }
  return $output;
}

/**
 * Retrieve the settings for a block
 *
 * @param int $delta The ID of the agenda
 * @param string $parameter The parameter required
 */
function agenda_settings($delta) {
  $res = db_query('SELECT name, value FROM {agenda} WHERE bid=%d', $delta);
  $settings = new stdClass();
  $settings->bid = $delta;
  while ($row = db_fetch_array($res)) {
    $settings->{$row['name']} = $row['value'];
  }
  if (!count($settings) || !isset($settings->title)) {
    $settings = FALSE;
  }
  return $settings;
}

/**
 * Get a variable
 *
 * @param int $delta The ID of the agenda
 * @param string $parameter The parameter required
 * @param string $default_value (optional) The default value
 */
function agenda_variable_get($delta, $parameter, $default_value) {
  $value = db_result(db_query("SELECT value FROM {agenda} WHERE bid=%d AND name='%s'", $delta, $parameter));
  if ($value === FALSE) {
    $value = $default_value;
  }
  return $value;
}

/**
 * Set a variable
 *
 * @param int $delta The ID of the agenda
 * @param string $parameter The parameter required
 * @param string $value The value
 */
function agenda_variable_set($delta, $parameter, $value) {
  $bid = db_result(db_query("SELECT bid FROM {agenda} WHERE bid=%d AND name='%s'", $delta, $parameter));
  if (!$bid) {
    $query = "INSERT INTO {agenda} (value,bid,name) VALUES ('%s', %d, '%s')";
  }
  else {
    $query = "UPDATE {agenda} SET value='%s' WHERE bid=%d AND name='%s'";
  }
  return db_query($query, $value, $delta, $parameter);
}

/**
 * Given a list of calendar IDs, parse out and return any event data
 *
 * @param array $block The block settings object
 * @param bool $cacheaction Whether to interact with the cache
 * @access private
 */
function agenda_get_events($block, $cache = TRUE) {

  // Check the cache
  if ($cache) {
    $cache_key = 'agenda_block_' . $block->bid;
    $eventdata = cache_get($cache_key, 'cache');
    if ($eventdata->expire > time()) {
      return $eventdata->data;
    }
  }

  // Get the calendars
  $calendars = preg_split('@\\r\\n?|\\n@', $block->calendars);
  $calendars = array_map('trim', $calendars);
  if (empty($calendars)) {
    return FALSE;
  }

  // Otherwise parse the calendars
  $eventdata = array();
  foreach ($calendars as $calindex => $googleid) {
    $calendar = _agenda_load_xml($googleid, $block);

    // If we fail to load the XML, handle it
    if (!$calendar) {
      watchdog('agenda', 'Unable to load the calendar feed (@feed) for block @bid', array(
        '@feed' => $googleid,
        '@bid' => $block->bid,
      ));
      continue;
    }

    // Parse out the event details
    foreach ($calendar->entry as $eventxml) {
      $event = _agenda_parse_event($eventxml, $block);
      if (!$event) {
        continue;
      }
      $event['index'] = (int) $calindex;
      $event['calendar'] = (string) $calendar->title;
      $eventdata[] = $event;
    }
  }

  // Sort the events by date
  $timestamps = array();
  foreach ($eventdata as $event) {
    $timestamps[] = $event['start timestamp'];
  }
  array_multisort($timestamps, SORT_NUMERIC, $eventdata);

  // Cache our data
  if ($cache) {
    $expires = time() + $block->cachetime;
    cache_set($cache_key, $eventdata, 'cache', $expires);
  }
  return $eventdata;
}

/**
 * Read useful event information from XML chunk
 *
 * @param SimpleXMLElement $xml An event node from a gData feed
 * @param object $block The settings object
 * @return array Associative array of information about the event
 * @access private
 */
function _agenda_parse_event($xml, $block) {
  $gd = $xml
    ->children('http://schemas.google.com/g/2005');

  // Build up information about the event
  $event = array();
  $event['title'] = htmlspecialchars((string) $xml->title);
  $event['where'] = htmlspecialchars((string) $gd->where
    ->attributes()->valueString);
  $event['description'] = _filter_autop(filter_xss((string) $xml->content));
  $event['start original'] = (string) $gd->when
    ->attributes()->startTime;
  $event['start timestamp'] = strtotime($gd->when
    ->attributes()->startTime);
  $event['start date'] = format_date($event['start timestamp'], $block->dateformat, $block->customdate);
  $event['start time'] = format_date($event['start timestamp'], $block->dateformat, $block->timeformat);
  $event['end original'] = (string) $gd->when
    ->attributes()->endTime;
  $event['end timestamp'] = strtotime($gd->when
    ->attributes()->endTime);
  $event['end date'] = format_date($event['end timestamp'], $block->dateformat, $block->customdate);
  $event['end time'] = format_date($event['end timestamp'], $block->dateformat, $block->timeformat);
  $event['published'] = format_date(strtotime($xml->published), $block->dateformat, $block->customdate);
  $event['updated'] = format_date(strtotime($xml->updated), $block->dateformat, $block->customdate);
  $link = (array) $xml->link[0];
  $event['url'] = (string) $link['@attributes']['href'];
  $event['link'] = l($block->linktext, $event['url']);

  // The day the event occurs on (without time) for grouping
  $event['when'] = format_date($event['start timestamp'], 'custom', 'Y-m-d');

  // If the Date API is installed, we can do better at DST times
  if (module_exists('date_api')) {
    $start = date_make_date($event['start timestamp'], NULL, DATE_UNIX);
    $event['start time'] = date_format_date($start, 'custom', $block->timeformat);
    $end = date_make_date($event['end timestamp'], NULL, DATE_UNIX);
    $event['end time'] = date_format_date($end, 'custom', $block->timeformat);
  }

  // Hide the start and end times for full day events
  if (strlen($gd->when
    ->attributes()->startTime) === 10) {
    $event['start time'] = '';
    $event['end time'] = '';
  }

  // Hide end date if it's the same as the start date
  if ($event['start timestamp'] === $event['end timestamp'] - 86400) {
    $event['end date'] = '';
  }
  return $event;
}

/**
 * Because we use keys for our public configuration, we want to
 * keep these keys in english, but display them translated. This function
 * provides a wrapper for this.
 */
function _agenda_translate($field) {
  $t['title'] = t('Title');
  $t['where'] = t('Where');
  $t['description'] = t('Description');
  $t['start original'] = t('Start original');
  $t['start timestamp'] = t('Start timestamp');
  $t['start date'] = t('Start date');
  $t['start time'] = t('Start time');
  $t['end original'] = t('End original');
  $t['end timestamp'] = t('End timestamp');
  $t['end date'] = t('End date');
  $t['end time'] = t('End time');
  $t['published'] = t('Published');
  $t['updated'] = t('Updated');
  $t['url'] = t('URL');
  $t['link'] = t('Link');
  $t['when'] = t('When');
  $t['calendar'] = t('Calendar');
  return $t[$field];
}

/**
 * Fetch the gData feed and parse the XML
 *
 * @param string $googleid The calendars Google ID
 * @param object $block The agenda block settings
 * @return object An object containing the status, request and result
 * @access private
 */
function _agenda_load_xml($googleid, $block) {
  $url = _agenda_feed_url($googleid, $block);
  $xml = drupal_http_request($url);
  $data = FALSE;
  if ($xml->code === '200') {
    $data = simplexml_load_string($xml->data);
  }
  return $data;
}

/**
 * Return the remote path to the google feed
 *
 * @param string $googleid The calendars Google ID
 * @param object $block The agenda block settings
 * @return object An object containing the status, request and result
 * @access private
 */
function _agenda_feed_url($googleid, $block) {
  $url = sprintf(AGENDA_SOURCEPATTERN, urlencode(check_plain($googleid)), date('Y-m-d', strtotime($block->start)), date('Y-m-d', strtotime($block->end)), $block->maxevents);
  return $url;
}

Functions

Namesort descending Description
agenda_block Implementation of hook_block().
agenda_display_block Generate the themed agenda block
agenda_get_events Given a list of calendar IDs, parse out and return any event data
agenda_help Implementation of hook_help().
agenda_init Implementation of hook_init().
agenda_menu Implementation of hook_menu().
agenda_perm Implementation of hook_perm().
agenda_settings Retrieve the settings for a block
agenda_theme Implementation of hook_theme().
agenda_variable_get Get a variable
agenda_variable_set Set a variable
_agenda_feed_url Return the remote path to the google feed
_agenda_load_xml Fetch the gData feed and parse the XML
_agenda_parse_event Read useful event information from XML chunk
_agenda_translate Because we use keys for our public configuration, we want to keep these keys in english, but display them translated. This function provides a wrapper for this.

Constants

Namesort descending Description
AGENDA_SOURCEPATTERN The google calendar feed address