? LICENSE.txt
? purl_includes.patch
Index: purl.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/purl/purl.module,v
retrieving revision 1.1.2.15
diff -u -p -r1.1.2.15 purl.module
--- purl.module	13 Aug 2009 04:12:42 -0000	1.1.2.15
+++ purl.module	8 Sep 2009 15:33:25 -0000
@@ -672,14 +672,10 @@ function _purl_options($active = true) {
     return $enabled_options;
   }
 
-  $options = array(
-    PURL_PATH => t('Path'),
-    PURL_PAIR => t('Keyed pair'),
-    PURL_DOMAIN => t('Full domain'),
-    PURL_SUBDOMAIN => t('Subdomain'),
-    PURL_EXTENSION => t('File extension'),
-    PURL_USERAGENT => t('User agent'),
-  );
+  $options = array();
+  foreach (purl_processors() as $id => $processor) {
+    $options[$id] = $processor['title'];
+  }
 
   if ($active) {
     $enabled_options = array();
@@ -750,11 +746,45 @@ class purl_cache {
  * Factory function to ease instantiation of modifier classes.
  */
 function purl_get_processor($method) {
+  purl_include($method);
   $modifier = "purl_$method";
   return new $modifier();
 }
 
 /**
+ * Load the class inc for a PURL method.
+ */
+function purl_include($method) {
+  static $loaded = array();
+  if (!isset($loaded[$method])) {
+    // Include parents recursively here.
+    $processors = purl_processors();
+    if (isset($processors[$method]['parent'])) {
+      purl_include($processors[$method]['parent']);
+    }
+
+    // Load the class inc.
+    module_load_include('inc', 'purl', 'includes/purl_'. $method);
+    $loaded[$method] = TRUE;
+  }
+}
+
+/**
+ * Return information about the available PURL processors.
+ * @TODO: Should this be a hook?
+ */
+function purl_processors() {
+  return array(
+    PURL_PATH => array('title' => t('Path')),
+    PURL_PAIR => array('title' => t('Keyed pair'), 'parent' => PURL_PATH),
+    PURL_DOMAIN => array('title' => t('Full domain')),
+    PURL_SUBDOMAIN => array('title' => t('Subdomain')),
+    PURL_EXTENSION => array('title' => t('File extension')),
+    PURL_USERAGENT => array('title' => t('User agent')),
+  );
+}
+
+/**
  * Helper function to determine if a url should be rewritten.
  *
  * @param $e
@@ -838,355 +868,6 @@ interface purl_processor {
 }
 
 /**
- * Path prefixer.
- */
-class purl_path implements purl_processor {
-
-  public function method() {
-    return PURL_PATH;
-  }
-
-  /**
-   * Detect a default value for 'q' when created.
-   */
-  public function detect() {
-    return isset($_REQUEST["q"]) ? trim($_REQUEST["q"], "/") : '';
-  }
-
-  public function description() {
-    return t('Choose a path. May contain only lowercase letters, numbers, dashes and underscores. e.g. "my-value"');
-  }
-
-  /**
-   * Tear apart the path and iterate thought it looking for valid values.
-   */
-  public function parse($valid_values, $q) {
-    $parsed = array();
-    $args = explode('/', $q);
-    $arg = current($args);
-    while (isset($valid_values[$arg])) {
-      $parsed[$arg] = $valid_values[$arg];
-      array_shift($args);
-      $arg = current($args);
-      if (in_array($arg, $parsed)) {
-        break;
-      }
-    }
-    return purl_path_elements($this, $parsed);
-  }
-
-  /**
-   * if $_GET and $_REQUEST are different, the path has NOT been
-   * aliased. We may need to rewrite the path.
-   */
-  public function adjust(&$q, $item) {
-    if ($_GET['q'] == trim($_REQUEST['q'], '/')) {
-      $q = $this->remove($q, $item);
-      // there is nothing beyond the path value -- treat as frontpage
-      if ($q == '') {
-        $_GET['q'] = variable_get('site_frontpage', 'node');
-      }
-      // pass the rest of the path onto Drupal cleanly
-      else {
-        $q = $_REQUEST['q'] = $_GET['q'] = _purl_get_normal_path($q);
-      }
-    }
-  }
-
-  /**
-   * Removes specific modifier from a query string.
-   *
-   * @param $q
-   *   The current path.
-   * @param $element
-   *   a purl_path_element object
-   * @return path string with the modifier removed.
-   */
-  function remove($q, $element) {
-    $args = explode('/', $q);
-
-    // Remove the value from the front of the query string
-    if (current($args) === (string) $element->value) {
-      array_shift($args);
-    }
-    return implode('/', $args);
-  }
-
-  /**
-   * Just need to add the value to the front of the path.
-   */
-  public function rewrite(&$path, &$options, $element) {
-
-    // We attempt to remove the prefix from the path as a way to detect it's
-    // presence. If the processor can remove itself than we're on a path alias
-    // that contains our prefix. Then $alt will not be the same as the $path 
-    // and we won't do any rewriting.
-    $alt = $this->remove($path, $element);
-
-    if ($alt == $path && !_purl_skip($element, $options)) {
-      $items = explode('/', $path);
-      array_unshift($items, $element->value);
-      $path = implode('/', $items);
-    }
-  }
-}
-
-/**
- * Pair pair prefixer.
- */
-class purl_pair extends purl_path {
-
-  public function method() {
-    return PURL_PAIR;
-  }
-
-  public function parse($valid_values, $q) {
-    $parsed = array();
-    $args = explode('/', $q);
-    $arg = $args[0];
-    while (isset($valid_values[$arg])) {
-      $parsed[$arg] = $valid_values[$arg];
-      array_shift($args);
-      $parsed[$arg]['id'] = array_shift($args);
-
-      $arg = $args[0];
-      if (in_array($arg, $parsed)) {
-        break;
-      }
-    }
-    return purl_path_elements($this, $parsed);
-  }
-
-  /**
-   * Removes specific modifier pair from a query string.
-   *
-   * @param $q
-   *   The current path.
-   * @param $element
-   *   a purl_path_element object
-   * @return path string with the pair removed.
-   */
-  function remove($q, $element) {
-    $args = explode('/', $q);
-    array_splice($args, array_search($element->value, $args), 2);
-    return implode('/', $args);
-  }
-
-  public function rewrite(&$path, &$options, $element) {
-    if (!_purl_skip($element, $options)) {
-      $items = explode('/', $path);
-      array_unshift($items, "{$element->value}/{$element->id}");
-      $path = implode('/', $items);
-    }
-  }
-}
-
-/**
- *  Full domain handling.
- */
-class purl_domain implements purl_processor {
-
-  function detect() {
-    return str_replace('http://','',$_SERVER['HTTP_HOST']);
-  }
-
-  public function method() {
-    return PURL_DOMAIN;
-  }
-
-  public function description() {
-    return t('Enter a domain registered for this context, such as "www.example.com".  Do not include http://');
-  }
-
-  /**
-   * Simply match our 'q' (aka domain) against an allowed value.
-   */
-  public function parse($valid_values, $q) {
-    $parsed = array();
-    if (isset($valid_values[$q])) {
-      $parsed[$q] = $valid_values[$q];
-    }
-    return purl_path_elements($this, $parsed);
-  }
-
-  public function adjust(&$value, $item) { return; }
-
-  /**
-   * Either force the url, or set it back to the base.
-   */
-  public function rewrite(&$path, &$options, $element) {
-    $options['absolute'] = TRUE;
-    if (!_purl_skip($element, $options)) {
-      $options['base_url'] = "http://{$element->value}";
-    }
-    else {
-      $options['base_url'] = variable_get('purl_base_domain', $base_url);
-    }
-  }
-}
-
-/**
- * Subdomain prefixing.
- */
-class purl_subdomain implements purl_processor {
-
-  function detect() {
-    $parts = explode('.', str_replace('http://','',$_SERVER['HTTP_HOST']));
-    return array_shift($parts);
-  }
-
-  public function method() {
-    return PURL_SUBDOMAIN;
-  }
-
-  public function description() {
-    return t('Enter a sub-domain for this context, such as "mygroup".  Do not include http://');
-  }
-
-  public function parse($valid_values, $q) {
-    $parsed = array();
-    if (isset($valid_values[$q])) {
-      $parsed[$q] = $valid_values[$q];
-    }
-    return purl_path_elements($this, $parsed);
-  }
-
-  public function adjust(&$value, $item) { return; }
-
-  public function rewrite(&$path, &$options, $element) {
-    $options['absolute'] = TRUE;
-    if (!_purl_skip($element, $options)) {
-      // Check to see if the link has already been treated.
-      $parts = explode('.', str_replace('http://','', $options['base_url']));
-      $possible = array_shift($parts);
-      $matches = purl_parse($this, $possible);
-
-      // If not add our subdomain.
-      if (!count($matches)) {
-        // ...but replace what we checked first.
-        array_unshift($parts, $possible);
-        array_unshift($parts, $element->value);
-
-        $options['absolute'] = TRUE;
-        $options['base_url'] = "http://". implode('.', $parts);
-      }
-    }
-    else {
-      $options['base_url'] = variable_get('purl_base_domain', $base_url);
-    }
-  }
-}
-
-/**
- * File extension style. Like ".csv"
- */
-class purl_extension implements purl_processor {
-
-  public function detect(){
-    $q = isset($_REQUEST["q"]) ? trim($_REQUEST["q"], "/") : '';
-    $last = explode('.', array_pop(explode('/', $q)));
-    if (count($last) > 1) {
-      return array_pop($last);
-    }
-    return '';
-  }
-
-  public function method() {
-    return PURL_EXTENSION;
-  }
-
-  public function description() {
-    return t('Enter a extension for this context, such as "csv".');
-  }
-
-  public function parse($valid_values, $q) {
-    $parsed = array();
-    $parsed = array();
-    if (isset($valid_values[$q])) {
-      $parsed[$q] = $valid_values[$q];
-    }
-    return purl_path_elements($this, $parsed);
-  }
-
-  /**
-   * if $_GET and $_REQUEST are different, the path has NOT been
-   * aliased. We may need to rewrite the path.
-   */
-  public function adjust(&$value, $item) {
-    if ($_GET['q'] == trim($_REQUEST['q'], '/')) {
-      $q = $this->remove($_GET['q'], $item);
-      // pass the rest of the path onto Drupal cleanly
-      $_REQUEST['q'] = $_GET['q'] = _purl_get_normal_path($q);
-    }
-  }
-
-  /**
-   * Remove our extension from the tail end of the path.
-   *
-   * @param $q
-   *   The current path.
-   * @param $element
-   *   a purl_path_element object
-   * @return path string with the extension removed.
-   */
-  public function remove($q, $element ) {
-    $args = explode('.', $q);
-    if (count($args > 1)) {
-      $extension = array_pop($args);
-      if ($element->value == $extension) {
-        return implode('.', $args);
-      }
-    }
-    return $q;
-  }
-
-  /**
-   * Because of the expected usage of the files extensions we don't provide
-   * a rewrite.
-   */
-  public function rewrite(&$path, &$options, $element) {}
-}
-
-/**
- * User agent style.
- */
-class purl_useragent implements purl_processor {
-  public function method() {
-    return 'useragent';
-  }
-
-  public function description() {
-    return t('Enter a user agent for this context, such as "iPhone".');
-  }
-
-  public function detect() {
-    $useragent = $_SERVER['HTTP_USER_AGENT'];
-    if (!empty($useragent)) {
-      return $useragent;
-    }
-    return '';
-  }
-
-  /**
-   * See a valid value is present in the HTTP_USER_AGENT. Note: we're using
-   * stripos() which makes this check relatively easy to pass..
-   */
-  public function parse($valid_values, $useragent) {
-    foreach ($valid_values as $key => $value) {
-      if (stripos($useragent, $key) !== FALSE) {
-        return purl_path_elements($this, $valid_values);
-      }
-    }
-  }
-
-  /**
-   * We cannot alter the user agent, not need to try.
-   */
-  public function adjust(&$value, $element) {}
-  public function rewrite(&$path, &$options, $element) {}
-}
-
-/**
  * Generate a array of purl_path_elements objects from parsed values.
  *
  * @param $processor
Index: includes/purl_domain.inc
===================================================================
RCS file: includes/purl_domain.inc
diff -N includes/purl_domain.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ includes/purl_domain.inc	8 Sep 2009 15:33:25 -0000
@@ -0,0 +1,46 @@
+<?php
+// $Id$
+
+/**
+ *  Full domain handling.
+ */
+class purl_domain implements purl_processor {
+
+  function detect() {
+    return str_replace('http://','',$_SERVER['HTTP_HOST']);
+  }
+
+  public function method() {
+    return PURL_DOMAIN;
+  }
+
+  public function description() {
+    return t('Enter a domain registered for this context, such as "www.example.com".  Do not include http://');
+  }
+
+  /**
+   * Simply match our 'q' (aka domain) against an allowed value.
+   */
+  public function parse($valid_values, $q) {
+    $parsed = array();
+    if (isset($valid_values[$q])) {
+      $parsed[$q] = $valid_values[$q];
+    }
+    return purl_path_elements($this, $parsed);
+  }
+
+  public function adjust(&$value, $item) { return; }
+
+  /**
+   * Either force the url, or set it back to the base.
+   */
+  public function rewrite(&$path, &$options, $element) {
+    $options['absolute'] = TRUE;
+    if (!_purl_skip($element, $options)) {
+      $options['base_url'] = "http://{$element->value}";
+    }
+    else {
+      $options['base_url'] = variable_get('purl_base_domain', $base_url);
+    }
+  }
+}
Index: includes/purl_extension.inc
===================================================================
RCS file: includes/purl_extension.inc
diff -N includes/purl_extension.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ includes/purl_extension.inc	8 Sep 2009 15:33:25 -0000
@@ -0,0 +1,72 @@
+<?php
+// $Id$
+
+/**
+ * File extension style. Like ".csv"
+ */
+class purl_extension implements purl_processor {
+
+  public function detect(){
+    $q = isset($_REQUEST["q"]) ? trim($_REQUEST["q"], "/") : '';
+    $last = explode('.', array_pop(explode('/', $q)));
+    if (count($last) > 1) {
+      return array_pop($last);
+    }
+    return '';
+  }
+
+  public function method() {
+    return PURL_EXTENSION;
+  }
+
+  public function description() {
+    return t('Enter a extension for this context, such as "csv".');
+  }
+
+  public function parse($valid_values, $q) {
+    $parsed = array();
+    $parsed = array();
+    if (isset($valid_values[$q])) {
+      $parsed[$q] = $valid_values[$q];
+    }
+    return purl_path_elements($this, $parsed);
+  }
+
+  /**
+   * if $_GET and $_REQUEST are different, the path has NOT been
+   * aliased. We may need to rewrite the path.
+   */
+  public function adjust(&$value, $item) {
+    if ($_GET['q'] == trim($_REQUEST['q'], '/')) {
+      $q = $this->remove($_GET['q'], $item);
+      // pass the rest of the path onto Drupal cleanly
+      $_REQUEST['q'] = $_GET['q'] = _purl_get_normal_path($q);
+    }
+  }
+
+  /**
+   * Remove our extension from the tail end of the path.
+   *
+   * @param $q
+   *   The current path.
+   * @param $element
+   *   a purl_path_element object
+   * @return path string with the extension removed.
+   */
+  public function remove($q, $element ) {
+    $args = explode('.', $q);
+    if (count($args > 1)) {
+      $extension = array_pop($args);
+      if ($element->value == $extension) {
+        return implode('.', $args);
+      }
+    }
+    return $q;
+  }
+
+  /**
+   * Because of the expected usage of the files extensions we don't provide
+   * a rewrite.
+   */
+  public function rewrite(&$path, &$options, $element) {}
+}
Index: includes/purl_pair.inc
===================================================================
RCS file: includes/purl_pair.inc
diff -N includes/purl_pair.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ includes/purl_pair.inc	8 Sep 2009 15:33:26 -0000
@@ -0,0 +1,52 @@
+<?php
+// $Id$
+
+/**
+ * Pair pair prefixer.
+ */
+class purl_pair extends purl_path {
+
+  public function method() {
+    return PURL_PAIR;
+  }
+
+  public function parse($valid_values, $q) {
+    $parsed = array();
+    $args = explode('/', $q);
+    $arg = $args[0];
+    while (isset($valid_values[$arg])) {
+      $parsed[$arg] = $valid_values[$arg];
+      array_shift($args);
+      $parsed[$arg]['id'] = array_shift($args);
+
+      $arg = $args[0];
+      if (in_array($arg, $parsed)) {
+        break;
+      }
+    }
+    return purl_path_elements($this, $parsed);
+  }
+
+  /**
+   * Removes specific modifier pair from a query string.
+   *
+   * @param $q
+   *   The current path.
+   * @param $element
+   *   a purl_path_element object
+   * @return path string with the pair removed.
+   */
+  function remove($q, $element) {
+    $args = explode('/', $q);
+    array_splice($args, array_search($element->value, $args), 2);
+    return implode('/', $args);
+  }
+
+  public function rewrite(&$path, &$options, $element) {
+    if (!_purl_skip($element, $options)) {
+      $items = explode('/', $path);
+      array_unshift($items, "{$element->value}/{$element->id}");
+      $path = implode('/', $items);
+    }
+  }
+}
Index: includes/purl_path.inc
===================================================================
RCS file: includes/purl_path.inc
diff -N includes/purl_path.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ includes/purl_path.inc	8 Sep 2009 15:33:26 -0000
@@ -0,0 +1,96 @@
+<?php
+// $Id$
+
+/**
+ * Path prefixer.
+ */
+class purl_path implements purl_processor {
+
+  public function method() {
+    return PURL_PATH;
+  }
+
+  /**
+   * Detect a default value for 'q' when created.
+   */
+  public function detect() {
+    return isset($_REQUEST["q"]) ? trim($_REQUEST["q"], "/") : '';
+  }
+
+  public function description() {
+    return t('Choose a path. May contain only lowercase letters, numbers, dashes and underscores. e.g. "my-value"');
+  }
+
+  /**
+   * Tear apart the path and iterate thought it looking for valid values.
+   */
+  public function parse($valid_values, $q) {
+    $parsed = array();
+    $args = explode('/', $q);
+    $arg = current($args);
+    while (isset($valid_values[$arg])) {
+      $parsed[$arg] = $valid_values[$arg];
+      array_shift($args);
+      $arg = current($args);
+      if (in_array($arg, $parsed)) {
+        break;
+      }
+    }
+    return purl_path_elements($this, $parsed);
+  }
+
+  /**
+   * if $_GET and $_REQUEST are different, the path has NOT been
+   * aliased. We may need to rewrite the path.
+   */
+  public function adjust(&$q, $item) {
+    if ($_GET['q'] == trim($_REQUEST['q'], '/')) {
+      $q = $this->remove($q, $item);
+      // there is nothing beyond the path value -- treat as frontpage
+      if ($q == '') {
+        $_GET['q'] = variable_get('site_frontpage', 'node');
+      }
+      // pass the rest of the path onto Drupal cleanly
+      else {
+        $q = $_REQUEST['q'] = $_GET['q'] = _purl_get_normal_path($q);
+      }
+    }
+  }
+
+  /**
+   * Removes specific modifier from a query string.
+   *
+   * @param $q
+   *   The current path.
+   * @param $element
+   *   a purl_path_element object
+   * @return path string with the modifier removed.
+   */
+  function remove($q, $element) {
+    $args = explode('/', $q);
+
+    // Remove the value from the front of the query string
+    if (current($args) === (string) $element->value) {
+      array_shift($args);
+    }
+    return implode('/', $args);
+  }
+
+  /**
+   * Just need to add the value to the front of the path.
+   */
+  public function rewrite(&$path, &$options, $element) {
+
+    // We attempt to remove the prefix from the path as a way to detect it's
+    // presence. If the processor can remove itself than we're on a path alias
+    // that contains our prefix. Then $alt will not be the same as the $path
+    // and we won't do any rewriting.
+    $alt = $this->remove($path, $element);
+
+    if ($alt == $path && !_purl_skip($element, $options)) {
+      $items = explode('/', $path);
+      array_unshift($items, $element->value);
+      $path = implode('/', $items);
+    }
+  }
+}
Index: includes/purl_subdomain.inc
===================================================================
RCS file: includes/purl_subdomain.inc
diff -N includes/purl_subdomain.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ includes/purl_subdomain.inc	8 Sep 2009 15:33:26 -0000
@@ -0,0 +1,54 @@
+<?php
+// $Id$
+
+/**
+ * Subdomain prefixing.
+ */
+class purl_subdomain implements purl_processor {
+
+  function detect() {
+    $parts = explode('.', str_replace('http://','',$_SERVER['HTTP_HOST']));
+    return array_shift($parts);
+  }
+
+  public function method() {
+    return PURL_SUBDOMAIN;
+  }
+
+  public function description() {
+    return t('Enter a sub-domain for this context, such as "mygroup".  Do not include http://');
+  }
+
+  public function parse($valid_values, $q) {
+    $parsed = array();
+    if (isset($valid_values[$q])) {
+      $parsed[$q] = $valid_values[$q];
+    }
+    return purl_path_elements($this, $parsed);
+  }
+
+  public function adjust(&$value, $item) { return; }
+
+  public function rewrite(&$path, &$options, $element) {
+    $options['absolute'] = TRUE;
+    if (!_purl_skip($element, $options)) {
+      // Check to see if the link has already been treated.
+      $parts = explode('.', str_replace('http://','', $options['base_url']));
+      $possible = array_shift($parts);
+      $matches = purl_parse($this, $possible);
+
+      // If not add our subdomain.
+      if (!count($matches)) {
+        // ...but replace what we checked first.
+        array_unshift($parts, $possible);
+        array_unshift($parts, $element->value);
+
+        $options['absolute'] = TRUE;
+        $options['base_url'] = "http://". implode('.', $parts);
+      }
+    }
+    else {
+      $options['base_url'] = variable_get('purl_base_domain', $base_url);
+    }
+  }
+}
Index: includes/purl_useragent.inc
===================================================================
RCS file: includes/purl_useragent.inc
diff -N includes/purl_useragent.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ includes/purl_useragent.inc	8 Sep 2009 15:33:26 -0000
@@ -0,0 +1,42 @@
+<?php
+// $Id$
+
+/**
+ * User agent style.
+ */
+class purl_useragent implements purl_processor {
+  public function method() {
+    return 'useragent';
+  }
+
+  public function description() {
+    return t('Enter a user agent for this context, such as "iPhone".');
+  }
+
+  public function detect() {
+    $useragent = $_SERVER['HTTP_USER_AGENT'];
+    if (!empty($useragent)) {
+      return $useragent;
+    }
+    return '';
+  }
+
+  /**
+   * See a valid value is present in the HTTP_USER_AGENT. Note: we're using
+   * stripos() which makes this check relatively easy to pass..
+   */
+  public function parse($valid_values, $useragent) {
+    foreach ($valid_values as $key => $value) {
+      if (stripos($useragent, $key) !== FALSE) {
+        return purl_path_elements($this, $valid_values);
+      }
+    }
+  }
+
+  /**
+   * We cannot alter the user agent, not need to try.
+   */
+  public function adjust(&$value, $element) {}
+  public function rewrite(&$path, &$options, $element) {}
+}
+
