Index: sfPatternRouting.class.php
===================================================================
--- sfPatternRouting.class.php	(revision 8748)
+++ sfPatternRouting.class.php	(working copy)
@@ -1,277 +1,13 @@
 <?php
 
-/*
- * This file is part of the symfony package.
- * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
 /**
- * sfPatternRouting class controls the generation and parsing of URLs.
+ * Proof of concept implementation for sfPopulatedRouting based on sfPatternRouting.
+ * Ideally should extend it.
  *
- * It maps an array of parameters to URLs definition. Each map is called a route.
- *
- * @package    symfony
- * @subpackage routing
- * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
- * @version    SVN: $Id$
  */
-class sfPatternRouting extends sfRouting
+class sfPopulatedRouting extends sfPatternRouting
 {
-  protected
-    $currentRouteName       = null,
-    $currentInternalUri     = array(),
-    $currentRouteParameters = null,
-    $defaultSuffix          = '',
-    $routes                 = array(),
-    $cacheData              = array(),
-    $cacheChanged           = false;
-
   /**
-   * Initializes this Routing.
-   *
-   * Available options:
-   *
-   *  * suffix:             The default suffix
-   *  * variable_prefixes:  An array of characters that starts a variable name (: by default)
-   *  * segment_separators: An array of allowed characters for segment separators (/ and . by default)
-   *  * variable_regex:     A regex that match a valid variable name ([\w\d_]+ by default)
-   *
-   * @see sfRouting
-   */
-  public function initialize(sfEventDispatcher $dispatcher, sfCache $cache = null, $options = array())
-  {
-    if (!isset($options['variable_prefixes']))
-    {
-      $options['variable_prefixes'] = array(':');
-    }
-
-    if (!isset($options['segment_separators']))
-    {
-      $options['segment_separators'] = array('/', '.');
-    }
-
-    if (!isset($options['variable_regex']))
-    {
-      $options['variable_regex'] = '[\w\d_]+';
-    }
-
-    $options['variable_prefix_regex']    = '(?:'.implode('|', array_map(create_function('$a', 'return preg_quote($a, \'#\');'), $options['variable_prefixes'])).')';
-    $options['segment_separators_regex'] = '(?:'.implode('|', array_map(create_function('$a', 'return preg_quote($a, \'#\');'), $options['segment_separators'])).')';
-    $options['variable_content_regex']   = '[^'.implode('', array_map(create_function('$a', 'return str_replace(\'-\', \'\-\', preg_quote($a, \'#\'));'), $options['segment_separators'])).']+';
-
-    if (!isset($options['load_configuration']))
-    {
-      $options['load_configuration'] = false;
-    }
-
-    $this->setDefaultSuffix(isset($options['suffix']) ? $options['suffix'] : '');
-
-    parent::initialize($dispatcher, $cache, $options);
-
-    if (!is_null($this->cache) && $cacheData = $this->cache->get('data'))
-    {
-      $this->cacheData = unserialize($cacheData);
-    }
-  }
-
-  /**
-   * @see sfRouting
-   */
-  public function loadConfiguration()
-  {
-    if (!is_null($this->cache) && $routes = $this->cache->get('symfony.routing.configuration'))
-    {
-      $this->routes = unserialize($routes);
-    }
-    else
-    {
-      if ($this->options['load_configuration'] && $config = sfContext::getInstance()->getConfigCache()->checkConfig('config/routing.yml', true))
-      {
-        include($config);
-      }
-
-      parent::loadConfiguration();
-
-      if (!is_null($this->cache))
-      {
-        $this->cache->set('symfony.routing.configuration', serialize($this->routes));
-      }
-    }
-  }
-
-  /**
-   * @see sfRouting
-   */
-  public function getCurrentInternalUri($withRouteName = false)
-  {
-    if (is_null($this->currentRouteName))
-    {
-      return null;
-    }
-
-    $typeId = $withRouteName ? 0 : 1;
-
-    if (!isset($this->currentInternalUri[$typeId]))
-    {
-      $parameters = $this->currentRouteParameters;
-
-      list($url, $regex, $variables, $defaults, $requirements) = $this->routes[$this->currentRouteName];
-
-      $internalUri = $withRouteName ? '@'.$this->currentRouteName : $parameters['module'].'/'.$parameters['action'];
-
-      $params = array();
-
-      // add parameters
-      foreach (array_keys($variables) as $variable)
-      {
-        if ($variable == 'module' || $variable == 'action')
-        {
-          continue;
-        }
-
-        $params[] = $variable.'='.(isset($parameters[$variable]) ? $parameters[$variable] : (isset($defaults[$variable]) ? $defaults[$variable] : ''));
-      }
-
-      // add * parameters if needed
-      if (false !== strpos($regex, '_star'))
-      {
-        foreach ($parameters as $key => $value)
-        {
-          if ($key == 'module' || $key == 'action' || isset($variables[$key]))
-          {
-            continue;
-          }
-
-          $params[] = $key.'='.$value;
-        }
-      }
-
-      // sort to guaranty unicity
-      sort($params);
-
-      $this->currentInternalUri[$typeId] = $internalUri.($params ? '?'.implode('&', $params) : '');
-    }
-
-    return $this->currentInternalUri[$typeId];
-  }
-
-  /**
-   * Sets the default suffix
-   *
-   * @param string The default suffix
-   */
-  public function setDefaultSuffix($suffix)
-  {
-    $this->defaultSuffix = '.' == $suffix ? '' : $suffix;
-  }
-
-  /**
-   * @see sfRouting
-   */
-  public function getRoutes()
-  {
-    return $this->routes;
-  }
-
-  /**
-   * @see sfRouting
-   */
-  public function setRoutes($routes)
-  {
-    return $this->routes = $routes;
-  }
-
-  /**
-   * @see sfRouting
-   */
-  public function hasRoutes()
-  {
-    return count($this->routes) ? true : false;
-  }
-
-  /**
-   * @see sfRouting
-   */
-  public function clearRoutes()
-  {
-    if ($this->options['logging'])
-    {
-      $this->dispatcher->notify(new sfEvent($this, 'application.log', array('Clear all current routes')));
-    }
-
-    $this->routes = array();
-  }
-
-  /**
-   * Returns true if the route name given is defined.
-   *
-   * @param string The route name
-   *
-   * @return  boolean
-   */
-  public function hasRouteName($name)
-  {
-    return isset($this->routes[$name]) ? true : false;
-  }
-
-  /**
-   * Adds a new route at the beginning of the current list of routes.
-   *
-   * @see connect
-   */
-  public function prependRoute($name, $route, $default = array(), $requirements = array())
-  {
-    $routes = $this->routes;
-    $this->routes = array();
-    $newroutes = $this->connect($name, $route, $default, $requirements);
-    $this->routes = array_merge($newroutes, $routes);
-
-    return $this->routes;
-  }
-
-  /**
-   * Adds a new route.
-   *
-   * Alias for the connect method.
-   *
-   * @see connect
-   */
-  public function appendRoute($name, $route, $default = array(), $requirements = array())
-  {
-    return $this->connect($name, $route, $default, $requirements);
-  }
-
-  /**
-   * Adds a new route before a given one in the current list of routes.
-   *
-   * @see connect
-   */
-  public function insertRouteBefore($pivot, $name, $route, $default = array(), $requirements = array())
-  {
-    if (!isset($this->routes[$pivot]))
-    {
-      throw new sfConfigurationException(sprintf('Unable to insert route "%s" before inexistent route "%s".', $name, $pivot));
-    }
-
-    $routes = $this->routes;
-    $this->routes = array();
-    $newroutes = array();
-    foreach ($routes as $key => $value)
-    {
-      if ($key == $pivot)
-      {
-        $newroutes = array_merge($newroutes, $this->connect($name, $route, $default, $requirements));
-      }
-      $newroutes[$key] = $value;
-    }
-
-    return $this->routes = $newroutes;
-  }
-
-  /**
    * Adds a new route at the end of the current list of routes.
    *
    * A route string is a string with 2 special constructions:
@@ -379,12 +115,8 @@
           // a variable (like :foo)
           $variable = $match[1];
 
-          if (!isset($requirements[$variable]))
-          {
-            $requirements[$variable] = $this->options['variable_content_regex'];
-          }
-
-          $segments[] = $currentSeparator.'(?P<'.$variable.'>'.$requirements[$variable].')';
+          //Removed requirement rexex for populated routing
+          $segments[] = $currentSeparator.'(?P<'.$variable.'>'.$this->options['variable_content_regex'].')';
           $currentSeparator = '';
 
           // for 1.0 BC, we don't take into account the default module and action variable
@@ -514,10 +246,11 @@
         // check requirements
         foreach ($requirements as $reqParam => $reqRegexp)
         {
+          /* removed for Populated Routing
           if (!is_null($tparams[$reqParam]) && !preg_match('#'.$reqRegexp.'#', $tparams[$reqParam]))
           {
             continue 2;
-          }
+          }*/
         }
 
         // all $params must be in $variables or $defaults if there is no * in route
@@ -647,6 +380,35 @@
         if (!is_int($key))
         {
           $out[$key] = urldecode($value);
+          if ($requirements[$key])
+          {
+            $callable = $requirements[$key];
+            $param = $out[$key];
+            $out[$key] = null;
+            //PopulatedRouting logic
+            if (is_callable($callable))
+            {
+              //is a static function
+              $out[$key] = call_user_func($callable,$param);
+            }
+            else
+            {
+              $callable = $callable.'Peer::retrieveByPk';
+              if (is_callable($callable))
+              {
+                //is a known DB object
+                $out[$key] = call_user_func($callable,$param);
+              }
+              else
+              {
+                throw new sfError404Exception(sprintf('Could not call "%s" with parameter "%s".', $requirements[$key], $param));
+              }
+            }
+            if (is_null($out[$key]))
+            {
+              throw new sfError404Exception(sprintf('Populating "%s" with parameter "%s" did not return any results.', $key, $param));
+            }
+          }
         }
       }
 
@@ -679,27 +441,4 @@
     return $this->currentRouteParameters;
   }
 
-  protected function parseStarParameter($star)
-  {
-    $parameters = array();
-    $tmp = explode('/', $star);
-    for ($i = 0, $max = count($tmp); $i < $max; $i += 2)
-    {
-      $parameters[$tmp[$i]] = isset($tmp[$i + 1]) ? urldecode($tmp[$i + 1]) : true;
-    }
-
-    return $parameters;
-  }
-
-  /**
-   * @see sfRouting
-   */
-  public function shutdown()
-  {
-    if (!is_null($this->cache) && $this->cacheChanged)
-    {
-      $this->cacheChanged = false;
-      $this->cache->set('symfony.routing.data', serialize($this->cacheData));
-    }
-  }
 }

