? 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 00:05:08 -0000
@@ -172,7 +172,7 @@ function custom_breadcrumbs_help($path, 
       $output = '<p>'. t("To create a custom breadcrumb, choose one of the breadcrumb types listed above. The following table lists all of the custom breadcrumbs that have been defined. The list can be filtered by breadcrumb type or language, or sorted by clicking on one of the column headings.") .'</p>';
       $output .= '<p>'. t('You can configure Custom Breadcrumb settings at <a href="@link">admin/settings/custom-breadcrumbs</a>.', array('@link' => url('admin/settings/custom-breadcrumbs'))) .'</p>';
       return $output;
-  } 
+  }
 }
 
 /**
@@ -202,14 +202,14 @@ function custom_breadcrumbs_form_alter(&
     $node = node_load($form['nid']['#value']);
     // Call custom_breadcrumbs_nodeapi to provide a custom_breadcrumb for this comment.
     custom_breadcrumbs_nodeapi($node, 'alter', array(), array(1));
-  } 
+  }
   elseif (user_access('administer custom breadcrumbs') && isset($form['type']) && isset($form['#node']) && $form['type']['#value'] .'_node_form' == $form_id) {
     // Provide a custom breadcrumbs fieldset for node edit forms.
     $node = $form['#node'];
     // Load all custom breadcrumbs for this node type.
     $breadcrumbs = custom_breadcrumbs_load_breadcrumbs('custom_breadcrumbs', 'custom_breadcrumb', array('node_type' => $form['type']['#value']));
     foreach (module_implements('cb_node_form_table') as $module) {
-      $func = $module .'_cb_node_form_table'; 
+      $func = $module .'_cb_node_form_table';
       $more = $func($node);
       if (!empty($more)) {
         $breadcrumbs = array_merge($breadcrumbs, $more);
@@ -240,12 +240,12 @@ function custom_breadcrumbs_form_alter(&
 /**
  * Select a breadcrumb from an array of breadcrumbs.
  *
- * @param $breadcrumbs 
+ * @param $breadcrumbs
  *   The array of breadcrumb objects that the breadcrumb will be selected from.
  * @param $obj
  *   An optional object (node, view, ...) to aid in the selection process.
  *
- * @return $breadcrumb 
+ * @return $breadcrumb
  *   The selected breadcrumb object.
  */
 function custom_breadcrumbs_select_breadcrumb($breadcrumbs, $objs = array()) {
@@ -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,18 +590,17 @@ 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_cb_identifiers_info();
+
+  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 +711,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 +1108,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
