You are here

follow.inc in Follow 7.2

Follow module API and helper functions.

File

follow.inc
View source
<?php

/**
 * @file
 * Follow module API and helper functions.
 */
define('FOLLOW_NAME', 0);
define('FOLLOW_ME', 1);
define('FOLLOW_US', 2);

/**
 * Helper function to generate the path to the follow css.
 */
function _follow_css_get_path() {
  $directory_path = file_stream_wrapper_get_instance_by_scheme('public')
    ->getDirectoryPath();
  return $directory_path . '/css/follow.css';
}

/**
 * Save the Follow module generated CSS.
 */
function follow_save_css($reset = FALSE) {

  // Destination where the file will be saved.
  $destination = 'public://css/follow.css';

  // Delete stale CSS file if necessary.
  if (file_exists($destination)) {
    drupal_delete_file_if_stale($destination);
  }

  // If reset is FALSE and the file exists, do nothing.
  if (!$reset && file_exists($destination)) {
    return TRUE;
  }

  // We have to prepare the directory, in case it doesn't exist.
  $directory = 'public://css';
  file_prepare_directory($directory, FILE_CREATE_DIRECTORY);

  // Clean out any existing aggregated CSS files.
  file_scan_directory($directory, '/.*/', array(
    'callback' => 'file_unmanaged_delete',
  ));

  // Generate a new CSS/JS token since we just wiped the CSS dir.
  _drupal_flush_css_js();

  // Load up the styles for each follow link type.
  $site_style = variable_get('follow_site_icon_style', 'small');
  $user_style = variable_get('follow_user_icon_style', 'small');
  $site_hide_text = variable_get('follow_site_hide_text', FALSE);
  $user_hide_text = variable_get('follow_user_hide_text', FALSE);
  $contents = "/**\n * This CSS file is generated by Follow module. DO NOT edit it directly.\n * Instead, copy the file to your theme's CSS directory and edit it there.\n */\n\n";
  $variables = array(
    'icon_style_name' => $site_style,
    'hide_text' => $site_hide_text,
  );
  $contents .= theme('follow_css', $variables);

  // If the user style is different, append it to our contents, with a selector
  // prefix to override the previous styles.
  if ($site_style != $user_style || $site_hide_text != $user_hide_text) {
    $variables = array(
      'icon_style_name' => $user_style,
      'hide_text' => $user_hide_text,
      'selector_prefix' => '.follow-links.user',
    );
    $contents .= theme('follow_css', $variables);
  }
  return file_unmanaged_save_data($contents, $destination, FILE_EXISTS_REPLACE);
}

/**
 * Helper function to create a link or block title.
 *
 * @param $uid
 *   The uid of the user account.  Defaults to the site form, $uid = 0.
 */
function follow_link_title($uid = 0) {

  // Check to see if we have a valid username.
  if ($uid) {
    $setting = variable_get('follow_user_block_title', FOLLOW_NAME);

    // Special handling for usernames.
    if ($setting == FOLLOW_NAME) {
      $account = user_load($uid);

      // Set plain to TRUE for realname module support.
      return t('Follow !name on', array(
        '!name' => theme('username', array(
          'account' => $account,
        )),
      ));
    }
    return t('Follow me on');
  }
  switch (variable_get('follow_site_block_title', FOLLOW_NAME)) {
    case FOLLOW_NAME:
      return t('Follow @name on', array(
        '@name' => variable_get('site_name', 'Drupal'),
      ));
    case FOLLOW_ME:
      return t('Follow me on');
    case FOLLOW_US:
      return t('Follow us on');
  }
}

/**
 * Helper function to build a follow links element.
 *
 * @param array $links
 *   An array of follow links.
 * @param array $networks
 *   An array of networks.
 * @param string $type
 *   The type of follow links, user or site.
 * @param string $alignment
 *   The alignment, horizontal or vertical.
 */
function _follow_links_element(array $links, array $networks, $type, $alignment = NULL) {

  // Let's be sure the CSS exists before printing this.
  follow_save_css();
  $element['follow-links']['#prefix'] = "<div class='follow-links clearfix {$type}'>";
  $element['follow-links']['#attached']['css'][] = _follow_css_get_path();
  if (!isset($alignment)) {
    $alignment = variable_get("follow_{$type}_alignment", 'vertical');
  }
  $wrapper = $alignment == 'horizontal' ? 'span' : 'div';
  foreach ($links as $link) {
    $title = !empty($link->title) ? $link->title : $networks[$link->name]['title'];
    $element['follow-links'][$link->name] = array(
      '#prefix' => "<{$wrapper} class='follow-link-wrapper follow-link-wrapper-{$link->name}'>",
      '#theme' => 'follow_link',
      '#link' => $link,
      '#title' => $title,
      '#suffix' => "</{$wrapper}>",
    );
  }
  $element['follow-links']['#suffix'] = '</div>';
  return $element;
}

/**
 * Like drupal_http_build_query() but without urlencodings.
 */
function follow_build_query(array $query, $parent = '') {
  $params = array();
  foreach ($query as $key => $value) {
    $key = $parent ? $parent . '[' . $key . ']' : $key;

    // Recurse into children.
    if (is_array($value)) {
      $params[] = follow_build_query($value, $key);
    }
    elseif (!isset($value)) {
      $params[] = $key;
    }
    else {
      $params[] = $key . '=' . $value;
    }
  }
  return implode('&', $params);
}

/**
 * Build a url for use in the form.
 */
function follow_build_url($path, $options) {
  $url = $path;
  if (!empty($options['query'])) {
    $url .= (strpos($path, '?') !== FALSE ? '&' : '?') . follow_build_query($options['query']);
  }
  if (!empty($options['fragment'])) {
    $url .= '#' . $options['fragment'];
  }
  return $url;
}

/**
 * Split a Drupal path or external link into path and options like a menu link.
 */
function follow_parse_url($url) {
  $parsed_url = parse_url($url);
  $defaults = array(
    'scheme' => '',
    'host' => '',
    'port' => '',
    'path' => '/',
    'query' => '',
    'fragment' => '',
  );
  $parsed_url += $defaults;
  $options = array(
    'query' => array(),
    'fragment' => $parsed_url['fragment'],
  );

  // Parse the query string into an array.
  parse_str($parsed_url['query'], $options['query']);
  if ($parsed_url['scheme']) {
    $parsed_url['scheme'] .= '://';
  }

  // Throw away port for now.
  $path = $parsed_url['scheme'] . $parsed_url['host'] . $parsed_url['path'];
  return array(
    'path' => $path,
    'options' => $options,
  );
}

/**
 * Validates the url field to verify it's actually a url.
 */
function follow_url_validate($form) {
  $url = trim($form['#value']);
  $networks = follow_networks_load($form['#follow_uid']);
  $info = $networks[$form['#follow_network']];
  $regex = follow_build_url_regex($info);
  $parsed = follow_parse_url($url);
  if ($url && !preg_match($regex, $parsed['path'])) {
    if (!empty($info['domain'])) {
      $message = t('The specified url is invalid for the domain %domain.  Make sure you use http://.', array(
        '%domain' => $info['domain'],
      ));
    }
    else {
      $message = t('The specified path is invalid.  Please enter a path on this site (e.g. rss.xml or taxonomy/term/1/feed).');
    }
    form_error($form, $message);
  }
}

/**
 * Build a regex to validate the url based on a known service url.
 */
function follow_build_url_regex($network_info) {
  if (!empty($network_info['domain'])) {

    // An external link.
    return '@^https?://([a-z0-9\\-_.]+\\.|)' . str_replace('.', '\\.', $network_info['domain']) . '/@i';
  }

  // An internal link should not have ':'.
  return '@^[^:]+$@';
}

/**
 * Loader function for individual links.
 *
 * @param $uid
 *   An int containing the uid of the user. uid 0 pulls the site follow links.
 * @return
 *   A single link in array format, or FALSE if none matched the incoming ID.
 */
function follow_links_load($uid = 0) {
  $links = array();
  $sql = "SELECT * FROM {follow_links} WHERE uid = :uid ORDER BY weight ASC";
  $result = db_query($sql, array(
    ':uid' => $uid,
  ));
  foreach ($result as $link) {
    $link->options = unserialize($link->options);
    $link->url = follow_build_url($link->path, $link->options);
    $links[$link->name] = $link;
  }
  return $links;
}

/**
 * Inserts a new link, or updates an existing one.
 *
 * @param $link
 *   A link object to be saved.
 */
function follow_link_save($link) {
  $parsed = follow_parse_url($link->url);
  $link->path = $parsed['path'];
  $link->options = $parsed['options'];
  if (isset($link->lid)) {
    drupal_write_record('follow_links', $link, 'lid');
  }
  else {
    drupal_write_record('follow_links', $link);
  }
  return $link;
}

/**
 * Deletes a link, given its unique ID.
 *
 * @param $lid
 *   An int containing the ID of a link.
 */
function follow_link_delete($lid) {
  db_delete('follow_links')
    ->condition('lid', $lid)
    ->execute();
}

/**
 * Loads all follow networks
 *
 * @param $uid
 *   The uid of the user. uid 0 pulls the site follow links.
 * @param $reset
 *   Boolean.  If TRUE, flushes the follow networks cache.
 *
 * @return
 *   An array of network names, keys are machine names, values are visible titles.
 */
function follow_networks_load($uid = 0, $reset = FALSE) {
  $networks =& drupal_static(__FUNCTION__, array());

  // Clear cache if $reset is TRUE;
  if ($reset) {
    $networks = array();
  }

  // Return presets if the array is populated.
  if (empty($networks[$uid])) {

    // We call hook_follow_networks_alter() to allow other modules to create
    // or alter networks.
    $networks[$uid] = follow_default_networks($uid);
    drupal_alter('follow_networks', $networks, $uid);
  }
  return $networks[$uid];
}

/**
 * Retrieves the default networks available.
 *
 * @return
 *   An associative array, keyed by the machine name. The values are an array
 *   including title of the network, along with the domain to be used for
 *   input validation of the network.
 */
function follow_default_networks($uid) {
  $networks = array(
    'facebook' => array(
      'title' => t('Facebook'),
      'domain' => 'facebook.com',
    ),
    'googleplus' => array(
      'title' => t('Google+'),
      'domain' => 'plus.google.com',
    ),
    'virb' => array(
      'title' => t('Virb'),
      'domain' => 'virb.com',
    ),
    'myspace' => array(
      'title' => t('MySpace'),
      'domain' => 'myspace.com',
    ),
    'twitter' => array(
      'title' => t('Twitter'),
      'domain' => 'twitter.com',
    ),
    'picasa' => array(
      'title' => t('Picasa'),
      'domain' => 'picasaweb.google.com',
    ),
    'flickr' => array(
      'title' => t('Flickr'),
      'domain' => 'flickr.com',
    ),
    'youtube' => array(
      'title' => t('YouTube'),
      'domain' => 'youtube.com',
    ),
    'vimeo' => array(
      'title' => t('Vimeo'),
      'domain' => 'vimeo.com',
    ),
    'bliptv' => array(
      'title' => t('blip.tv'),
      'domain' => 'blip.tv',
    ),
    'lastfm' => array(
      'title' => t('last.fm'),
      'domain' => 'last.fm',
    ),
    'linkedin' => array(
      'title' => t('LinkedIn'),
      'domain' => 'linkedin.com',
    ),
    'delicious' => array(
      'title' => t('Delicious'),
      'domain' => 'delicious.com',
    ),
    'tumblr' => array(
      'title' => t('Tumblr'),
      'domain' => 'tumblr.com',
    ),
    'viadeo' => array(
      'title' => t('Viadeo'),
      'domain' => 'viadeo.com',
    ),
    'xing' => array(
      'title' => t('Xing'),
      'domain' => 'xing.com',
    ),
    'spiceworks' => array(
      'title' => t('Spiceworks'),
      'domain' => 'spiceworks.com',
    ),
    'instagram' => array(
      'title' => t('Instagram'),
      'domain' => 'instagram.com',
    ),
    'pinterest' => array(
      'title' => t('Pinterest'),
      'domain' => 'pinterest.com',
    ),
  );
  if ($uid == 0) {
    $networks['this-site'] = array(
      'title' => t('This site (RSS)'),
      'domain' => '',
    );
    $networks['newsletter'] = array(
      'title' => t('Newsletter'),
      'domain' => '',
    );
  }
  return $networks;
}

/**
 * Load up all icon styles. You can add or alter these icon styles in a module
 * or theme by implementing hook_follow_icon_styles_alter(). See follow.api.php
 * for an example.
 */
function follow_icon_styles() {
  $styles =& drupal_static(__FUNCTION__);
  if (!isset($styles)) {
    $styles = follow_default_icon_styles();
    drupal_alter('follow_icon_styles', $styles);
  }
  return $styles;
}

/**
 * Load up a single icon style. If no icon style is found with the given name,
 * the small icon style will be returned.
 *
 * @param string $name
 *   The string machine name of the style.
 */
function follow_get_icon_style($name) {
  $styles = follow_icon_styles();
  return isset($styles[$name]) ? $styles[$name] : $styles['small'];
}

/**
 * Default icon styles provided by follow module.
 */
function follow_default_icon_styles() {
  $styles['small'] = array(
    'name' => 'small',
    'label' => t('Small'),
  );
  $styles['large'] = array(
    'name' => 'large',
    'label' => t('Large'),
    'css-overrides' => array(
      'height: 42px;',
      'line-height: 38px;',
      'padding-left: 39px;',
      'padding-right: 5px;',
    ),
  );
  $styles['wpzoom26'] = array(
    'name' => 'wpzoom26',
    'label' => t('WPZOOM 26x'),
    'css-overrides' => array(
      'height: 32px;',
      'line-height: 28px;',
      'padding-left: 30px;',
      'padding-right: 3px;',
    ),
  );
  $styles['wpzoom38'] = array(
    'name' => 'wpzoom38',
    'label' => t('WPZOOM 38x'),
    'css-overrides' => array(
      'height: 44px;',
      'line-height: 40px;',
      'padding-left: 41px;',
      'padding-right: 5px;',
    ),
  );
  $styles['paulrobertlloyd32'] = array(
    'name' => 'paulrobertlloyd32',
    'label' => t('Paul Robert Lloyd 32x32'),
    'css-overrides' => array(
      'height: 38px;',
      'line-height: 34px;',
      'padding-left: 38px;',
      'padding-right: 5px;',
    ),
  );
  return $styles;
}

/**
 * Return an array of icon style options, with the key being the machine name of
 * the style, and the value being the label of the style.
 */
function follow_icon_style_options() {
  $options = array();
  foreach (follow_icon_styles() as $style) {
    if (!isset($style['name']) || !isset($style['label'])) {
      continue;
    }
    $options[$style['name']] = $style['label'];
  }
  return $options;
}

/**
 * Helper function to determine the icon path for a icon style.
 *
 * @param array $style
 *   The style to check.
 */
function _follow_style_icon_path(array $style) {
  $default_icon_path = drupal_get_path('module', 'follow') . '/icons/' . $style['name'];
  $path = !empty($style['icon-path']) ? $style['icon-path'] : $default_icon_path;
  return base_path() . $path;
}

Functions

Namesort descending Description
follow_build_query Like drupal_http_build_query() but without urlencodings.
follow_build_url Build a url for use in the form.
follow_build_url_regex Build a regex to validate the url based on a known service url.
follow_default_icon_styles Default icon styles provided by follow module.
follow_default_networks Retrieves the default networks available.
follow_get_icon_style Load up a single icon style. If no icon style is found with the given name, the small icon style will be returned.
follow_icon_styles Load up all icon styles. You can add or alter these icon styles in a module or theme by implementing hook_follow_icon_styles_alter(). See follow.api.php for an example.
follow_icon_style_options Return an array of icon style options, with the key being the machine name of the style, and the value being the label of the style.
follow_links_load Loader function for individual links.
follow_link_delete Deletes a link, given its unique ID.
follow_link_save Inserts a new link, or updates an existing one.
follow_link_title Helper function to create a link or block title.
follow_networks_load Loads all follow networks
follow_parse_url Split a Drupal path or external link into path and options like a menu link.
follow_save_css Save the Follow module generated CSS.
follow_url_validate Validates the url field to verify it's actually a url.
_follow_css_get_path Helper function to generate the path to the follow css.
_follow_links_element Helper function to build a follow links element.
_follow_style_icon_path Helper function to determine the icon path for a icon style.

Constants

Namesort descending Description
FOLLOW_ME
FOLLOW_NAME @file Follow module API and helper functions.
FOLLOW_US