? custom_breadcrumbs.identifiers.inc
Index: custom_breadcrumbs.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/custom_breadcrumbs/custom_breadcrumbs.module,v
retrieving revision 1.6.2.5.2.35
diff -u -p -r1.6.2.5.2.35 custom_breadcrumbs.module
--- custom_breadcrumbs.module	21 Mar 2010 01:08:57 -0000	1.6.2.5.2.35
+++ custom_breadcrumbs.module	27 Mar 2010 02:33:40 -0000
@@ -267,49 +267,11 @@ function custom_breadcrumbs_select_bread
  */
 function custom_breadcrumbs_set_breadcrumb($breadcrumb, $objs = array()) {
   if ($breadcrumb && !custom_breadcrumbs_exclude_path()) {
-    $location = array();
-    $trail = custom_breadcrumbs_home_crumb();
-    if (!empty($trail)) {
-      $title = variable_get('custom_breadcrumb_home', t('Home'));
-      $location = array('title' => variable_get('custom_breadcrumb_home', t('Home')), 'href' => '<front>', 'localized_options' => array());
-    }
-    if (variable_get('custom_breadcrumbs_use_php_in_titles', FALSE)) {
-      $titles = extract_php($breadcrumb->titles, $objs);
-      // Titles and paths arrays can also be provided as elements of an associative array.
-      if (isset($titles['titles']) && is_array($titles['titles']) && isset($titles['paths']) && is_array($titles['paths'])) {
-        $paths = $titles['paths'];
-        $titles = $titles['titles'];
-      }
-      else {
-        $paths = extract_php($breadcrumb->paths, $objs);
-      }
-    }
-    if (!isset($titles) || is_null($titles)) {
-      $titles = preg_split("/[\n]+/", $breadcrumb->titles);
-    }
-    if (!isset($paths) || is_null($paths)) {
-      $paths = preg_split("/[\n]+/", $breadcrumb->paths);
-    }
-
-    if (module_exists('token')) {
-      // Do token replacement.
-      $types = custom_breadcrumbs_token_types($objs);
-      $titles = token_replace_multiple($titles, $types);
-      $paths = token_replace_multiple($paths, $types);
-    }
-  
-    for ($i = 0; $i < count($titles); $i++) {
-      $title = trim($titles[$i]);
-      if (($title != '') && ($title != '<none>')) {
-        // Create breadcrumb only if there is a title.
-        // Include optional html attributes.
-        $options = _custom_breadcrumbs_identifiers_option($i+1, $breadcrumb->bid);
-        $trail[] = _custom_breadcrumbs_create_crumb($title, trim($paths[$i]), $options);
-        $location[] = array('title' => $title, 'href' => drupal_get_normal_path(trim($paths[$i])));
-      }
-    }
+    $locations = array();
+    $trail = _custom_breadcrumbs_get_breadcrumb($breadcrumb, $objs, $locations);
+
     if (variable_get('custom_breadcrumbs_force_active_trail', FALSE)) {
-      menu_set_active_trail($location);
+      menu_set_active_trail($locations);
     }
     drupal_set_breadcrumb($trail);
     // Optionally save the unique breadcrumb id of the last set breadcrumb.
@@ -318,6 +280,118 @@ function custom_breadcrumbs_set_breadcru
 }
 
 /**
+ * Helper function to get custom breadcrumb.
+ *
+ * This function is used to retrieve the breadcrumb trail before actually setting it.
+ * @see custom_breadcrumbs_get_breadcrumb().
+ *
+ * @param $breadcrumb
+ *   The breadcrumb object
+ * @param $obj
+ *   A node object (if available) for building token substituions.
+ * @param $locations
+ *   Locations array to be able to set active menu trail - will be passed by
+ *   reference.
+ * @param $fill_locations
+ *   this have to be set to TRUE, to write to $locations, so the items can be
+ *   populated for menu set active trail.
+ *
+ * @return
+ *   array of html crumbs
+ */
+function _custom_breadcrumbs_get_breadcrumb($breadcrumb, $objs, &$locations, $fill_locations = FALSE) {
+  // Assure locations as array
+  if (!is_array($locations)) {
+    $locations = array();
+  }
+  // avoid invalid nesting
+  elseif (isset($locations['title']) || isset($locations['href'])) {
+    $locations = array($locations);
+  }
+
+  $trail = custom_breadcrumbs_home_crumb();
+  if (!empty($trail)) {
+    $title = variable_get('custom_breadcrumb_home', t('Home'));
+    $locations[] = array('title' => variable_get('custom_breadcrumb_home', t('Home')), 'href' => '<front>', 'localized_options' => array());
+  }
+
+  if (variable_get('custom_breadcrumbs_use_php_in_titles', FALSE)) {
+    $titles = extract_php($breadcrumb->titles, $objs);
+    // Titles and paths arrays can also be provided as elements of an associative array.
+    if (isset($titles['titles']) && is_array($titles['titles']) && isset($titles['paths']) && is_array($titles['paths'])) {
+      $paths = $titles['paths'];
+      $titles = $titles['titles'];
+    }
+    else {
+      $paths = extract_php($breadcrumb->paths, $objs);
+    }
+  }
+  if (!isset($titles) || is_null($titles)) {
+    $titles = preg_split("/[\n]+/", $breadcrumb->titles);
+  }
+  if (!isset($paths) || is_null($paths)) {
+    $paths = preg_split("/[\n]+/", $breadcrumb->paths);
+  }
+
+  // Token replacement for titles and paths
+  if (module_exists('token')) {
+    // Do token replacement.
+    $types = custom_breadcrumbs_token_types($objs);
+    $titles = token_replace_multiple($titles, $types);
+    $paths = token_replace_multiple($paths, $types);
+  }
+
+  // Build trail
+  $items = _custom_breadcrumbs_get_trail_items($breadcrumb, $titles, $paths);
+
+  $breadcrumbs = array();
+
+  // Run the returned items
+  foreach($items as $item) {
+    if ($item['crumb']) $breadcrumbs[] = $item['crumb'];
+    if ($set_active_trail) {
+      $location[] = array('title' => $item['title'], 'href' => drupal_get_normal_path(trim($item['href'])));
+    }
+  }
+  return $breadcrumbs;
+}
+
+/**
+ * Builds the trail items for a given breadcrumb specification.
+ *
+ * Implementation of special identifiers will be considered.
+ *
+ * @param $breadcrumb
+ *   The breadcrumb object
+ * @param $titles
+ *   array of titles (after token replacement)
+ * @param $paths
+ *   array of paths (after token replacement), may contain special identifiers
+ *
+ * @return
+ *   array of trail items
+ *   each item consists of
+ *   - 'title' - Title of the item
+ *   - 'href' - path of the item to be able to set active trail
+ *   - 'crumb' => the actual representation in breadcrumbs
+ */
+function _custom_breadcrumbs_get_trail_items($breadcrumb, $titles, $paths) {
+  $trail_items = array();
+  // run each line
+  for ($i = 0; $i < count($titles); $i++) {
+    $title = trim($titles[$i]);
+    if (($title != '') && ($title != '<none>')) {
+      // Create breadcrumb only if there is a title.
+      // Include optional html attributes.
+      $options = _custom_breadcrumbs_identifiers_option($i+1, $breadcrumb->bid);
+      $crumb_items = _custom_breadcrumbs_create_crumb_items($title, trim($paths[$i]), $options);
+      $trail_items = array_merge($trail_items, $crumb_items);
+    }
+  }
+  return $trail_items;
+}
+
+/**
  *  Set or get the unique breadcrumb id.
  *
  *  @param $type
@@ -410,8 +484,8 @@ function _custom_breadcrumbs_save_breadc
  *   Any additional submodule function to call after breadcrumb has been deleted.
  */
 function _custom_breadcrumbs_delete_breadcrumb($module, $key, $bid) {
-  $info = module_invoke($module, 'cb_breadcrumb_info'); 
-  if (isset($info[$key]['table'])) {  
+  $info = module_invoke($module, 'cb_breadcrumb_info');
+  if (isset($info[$key]['table'])) {
     db_query('DELETE FROM {'. $info[$key]['table'] .'} WHERE bid = %d', $bid);
   }
 }
@@ -436,53 +510,75 @@ function custom_breadcrumbs_home_crumb()
 }
 
 /**
- * Private function for custom breadcrumb to create a crumb item.
+ * Creates one ore more crumb items out of a custom bread crumb definition line.
  *
  * @param $title
- *   The human readable title to be rendered by the browser.
+ *  title line string of custom breadcrumb definition, after token replacement
  * @param $original_path
- *   The desired URI and/or special identifier.
- * @param $attr
- *   An associative array containing the HTML attributes to apply to the anchor tag.
- *
- * @return
- *   An HTML string containing a link to the original path.
- */
-function _custom_breadcrumbs_create_crumb($title, $original_path, $attr = array()) {
+ *  path line string of custom breadcrumb definition, after token replacment,
+ *  can contain a special identifier
+ * @param $attributes
+ *  additional attributes for the breadcrumb item
+ * @return
+ *   array of one or multiple crumb items
+ *   - in most cases , especially without an identifier it is only an array of
+ *     one item
+ */
+function _custom_breadcrumbs_create_crumb_items($title, $original_path, $attributes = array()) {
+  // The list to return
+  $crumbs = array();
+
   // Decode title to properly handle special characters.
   $title = decode_entities($title);
   // Collapse double slashes to one.
   $original_path = preg_replace('/\/+/', '/', $original_path);
   // Removing leading and trailing slashes.
   $original_path = preg_replace('/^\/|\/+$/', '', $original_path);
+
   list($identifier, $path) = explode("|", $original_path, 2);
-  if (isset($path) && $path !== '') {
-    $options = parse_url($path);
-    $options = array_merge($options, $attr);
-    switch (trim($identifier)) {
-      case '<pathauto>':
-        if (module_exists('pathauto')) {
-          module_load_include('inc', 'pathauto', 'pathauto');
-          $crumb = l($title, pathauto_cleanstring($options['path'], FALSE), $options);
-        }
-        break;
-      default:
-        $crumb = l($title, $options['path'], $options);
+  $identifier = trim($identifier);
+  // Get Information of identifier
+  $info = custom_breadcrumbs_get_identifiers($identifier);
+
+  // If $identifier is valid identifier
+  if ($info) {
+    // Load extra file specified for callback.
+    if ($info['file'] && is_file('./'. $info['file'])) {
+      require_once './'. $info['file'];
+    }
+    // Call identifier callback to build crumb items
+    $callback = $info['callback'];
+    $return = $callback($title, $path, $attributes, $identifier);
+
+    // Ease return values for callbacks:
+    if (!is_array($return)) {
+      $crumbs[] = array(
+        'crumb' => $return,
+        'title' => $title,
+        'href' => $path,
+      );
+    }
+    elseif (isset($return['crumb']) || isset($return['title']) || isset($return['href'])) {
+      $crumbs[] = $return;
+    }
+    else {
+      $crumbs = $return;
     }
   }
   else {
-    // This may be just be a single identifier.
-    $options = parse_url($original_path);
-    $options = array_merge($options, $attr);
-    switch ($identifier) {
-      case '<none>':
-        $crumb = check_plain($title);
-        break;
-      default:
-        $crumb = l($title, $options['path'], $options);
+    // Use original path, if no pipe was given
+    if (!isset($path)) {
+      $path = $original_path;
     }
+    $options = parse_url($path);
+    $options = array_merge($options, $attributes);
+    $crumbs[] = array(
+      'crumb' => l($title, $options['path'], $options),
+      'title' => $title,
+      'href' => $options['path'],
+    );
   }
-  return $crumb;
+  return $crumbs;
 }
 
 /**
@@ -494,16 +590,14 @@ function theme_custom_breadcrumbs_help_i
   $headers = array(t('Identifier'), t('Behaviour'));
   $rows = array();
   $row = array();
-  // <none> identifier.
-  $row[] = check_plain('<none>');
-  $row[] = t('This will result in a plain text crumb. This identifier should not be used with the pipe (|) symbol.');
-  $rows[] = $row;
 
-  // <pathauto> identifier.
-  if (module_exists('pathauto')) {
-    $row = array();
-    $row[] = check_plain('<pathauto>');
-    $row[] = t('Cleans the given path using your pathauto replacement rules.');
+  $identifiers = custom_breadcrumbs_get_identifiers();
+
+  foreach ($identifiers as $id => $spec) {
+    $rows[] = array(
+      check_plain($id),
+      $spec['help'], // is allowed to contain html
+    );
     $rows[] = $row;
   }
   return theme('table', $headers, $rows, array('class' => 'description'));
@@ -616,7 +710,7 @@ function _custom_breadcrumbs_load_all_br
 
 /**
  * Set the breadcrumb trail to match the menu structure.
- * 
+ *
  * This function uses the same approach as in the menu_breadcrumb module.
  */
 function custom_breadcrumbs_set_menu_breadcrumb() {
@@ -1013,3 +1107,58 @@ function _custom_breadcrumbs_identifiers
   }
   return $options;
 }
+
+/**
+ * Retrieve defined special identifiers for custom breadcumb paths.
+ *
+ * @param $identifier
+ *   (optional) identifier to retrieve specification for
+ *
+ * @return
+ *   array of specifications - or single specification for given $identifier
+ */
+function custom_breadcrumbs_get_identifiers($identifier = NULL) {
+  static $cache;
+  if (empty($cache)) {
+    $identifiers = module_invoke_all('cb_identifiers_info');
+    $cache = $identifiers;
+  }
+
+  // Only return single identifier
+  if (isset($identifier)) {
+    return (isset($cache[$identifier])) ? $cache[$identifier] : FALSE;
+  }
+
+  return $cache;
+}
+
+/**
+ * Implementation of hook_cb_identifiers_info().
+ *
+ * @return
+ *   array of identifier items
+ *   each item consisists of identifer as key and a values array of:
+ *   - 'title' - for identifier
+ *   - 'help' - help text for custom breacrumb add/edit page in
+ *   - 'callback' - function that builds the crumb item
+ *      @see _custom_breadcrumbs_identifier_none()
+ *   - 'file' - (optional) - location of the file the callback is located in
+ */
+function custom_breadcrumbs_cb_identifiers_info() {
+  $identifiers = array();
+  $identifiers['<none>'] = array(
+    'title' => t('Plain text crumb'),
+    'help' => t('This will result in a plain text crumb. This identifier should not be used with the pipe (|) symbol.'),
+    'callback' => '_custom_breadcrumbs_identifier_none',
+    'file' => drupal_get_path('module','custom_breadcrumbs') .'/custom_breadcrumbs.identifiers.inc',
+  );
+  if (module_exists('pathauto')) {
+    $identifiers['<pathauto>'] = array(
+      'title' => t('Pathauto'),
+      'help' => t('Cleans the given path using your pathauto replacement rules.'),
+      'callback' => '_custom_breadcrumbs_identifier_pathauto',
+      'file' => drupal_get_path('module','custom_breadcrumbs') .'/custom_breadcrumbs.identifiers.inc',
+    );
+  }
+  return $identifiers;
+}
\ No newline at end of file
