Development

Changeset 12969

You must first sign up to be able to contribute.

Changeset 12969

Show
Ignore:
Timestamp:
11/13/08 12:29:35 (8 months ago)
Author:
fabien
Message:

[1.2] fixed URL generation when custom tokens have been defined

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/1.2/lib/routing/sfRoute.class.php

    r12968 r12969  
    3232    $defaults          = array(), 
    3333    $requirements      = array(), 
    34     $tokens            = array(); 
     34    $tokens            = array(), 
     35    $customToken       = false; 
    3536 
    3637  /** 
     
    211212    } 
    212213 
    213     if ($this->options['generate_shortest_url']) 
    214     { 
    215       // construct the shortest URL possible 
    216       $url = array(); 
    217       $optional = true; 
    218       $first = true; 
    219       $tokens = array_reverse($this->tokens); 
    220       foreach ($tokens as $token) 
    221       { 
    222         switch ($token[0]) 
    223         { 
    224           case 'variable': 
    225             if (!$optional || !isset($this->defaults[$token[3]]) || $tparams[$token[3]] != $this->defaults[$token[3]]) 
    226             { 
    227               $url[] = urlencode($tparams[$token[3]]); 
    228               $optional = false; 
    229             } 
    230             break; 
    231           case 'text': 
    232             $url[] = $token[2]; 
    233             $optional = false; 
    234             break; 
    235           case 'separator': 
    236           default: 
    237             if (false === $optional || $first) 
    238             { 
    239               $url[] = $token[2]; 
    240             } 
    241             break; 
    242         } 
    243  
    244         $first = false; 
    245       } 
    246  
    247       $url = implode('', array_reverse($url)); 
    248       if (!$url) 
    249       { 
    250         $url = '/'; 
    251       } 
     214    if ($this->options['generate_shortest_url'] || $this->customToken) 
     215    { 
     216      $url = $this->generateWithTokens($tparams); 
    252217    } 
    253218    else 
     
    278243 
    279244  /** 
     245   * Generates a URL for the given parameters by using the route tokens. 
     246   * 
     247   * @param array $parameters An array of parameters 
     248   */ 
     249  protected function generateWithTokens($parameters) 
     250  { 
     251    $url = array(); 
     252    $optional = $this->options['generate_shortest_url']; 
     253    $first = true; 
     254    $tokens = array_reverse($this->tokens); 
     255    foreach ($tokens as $token) 
     256    { 
     257      switch ($token[0]) 
     258      { 
     259        case 'variable': 
     260          if (!$optional || !isset($this->defaults[$token[3]]) || $parameters[$token[3]] != $this->defaults[$token[3]]) 
     261          { 
     262            $url[] = urlencode($parameters[$token[3]]); 
     263            $optional = false; 
     264          } 
     265          break; 
     266        case 'text': 
     267          $url[] = $token[2]; 
     268          $optional = false; 
     269          break; 
     270        case 'separator': 
     271          if (false === $optional || $first) 
     272          { 
     273            $url[] = $token[2]; 
     274          } 
     275          break; 
     276        default: 
     277          // handle custom tokens 
     278          if ($segment = call_user_func_array(array($this, 'generateFor'.ucfirst(array_shift($token))), array_merge(array($optional, $parameters), $token))) 
     279          { 
     280            $url[] = $segment; 
     281            $optional = false; 
     282          } 
     283          break; 
     284      } 
     285 
     286      $first = false; 
     287    } 
     288 
     289    $url = implode('', array_reverse($url)); 
     290    if (!$url) 
     291    { 
     292      $url = '/'; 
     293    } 
     294 
     295    return $url; 
     296  } 
     297 
     298  /** 
    280299   * Returns the compiled pattern. 
    281300   * 
     
    423442  } 
    424443 
     444  /** 
     445   * Pre-compiles a route. 
     446   */ 
    425447  protected function preCompile() 
    426448  { 
     
    432454  } 
    433455 
     456  /** 
     457   * Post-compiles a route. 
     458   */ 
    434459  protected function postCompile() 
    435460  { 
     
    443468  } 
    444469 
     470  /** 
     471   * Tokenizes the route. 
     472   */ 
    445473  protected function tokenize() 
    446474  { 
     
    455483      if (false !== $this->tokenizeBufferBefore($buffer, $tokens, $afterASeparator, $currentSeparator)) 
    456484      { 
     485        // a custom token 
     486        $this->customToken = true; 
    457487      } 
    458488      else if ($afterASeparator && preg_match('#^'.$this->options['variable_prefix_regex'].'('.$this->options['variable_regex'].')#', $buffer, $match)) 
     
    485515      else if (false !== $this->tokenizeBufferAfter($buffer, $tokens, $afterASeparator, $currentSeparator)) 
    486516      { 
     517        // a custom token 
     518        $this->customToken = true; 
    487519      } 
    488520      else 
     
    494526  } 
    495527 
     528  /** 
     529   * Tokenizes the buffer before default logic is applied. 
     530   * 
     531   * This method must return false if the buffer has not been parsed. 
     532   * 
     533   * @param string   $buffer           The current route buffer 
     534   * @param array    $tokens           An array of current tokens 
     535   * @param Boolean  $afterASeparator  Whether the buffer is just after a separator 
     536   * @param string   $currentSeparator The last matched separator 
     537   * 
     538   * @return Boolean true if a token has been generated, false otherwise 
     539   */ 
    496540  protected function tokenizeBufferBefore(&$buffer, &$tokens, &$afterASeparator, &$currentSeparator) 
    497541  { 
     
    499543  } 
    500544 
     545  /** 
     546   * Tokenizes the buffer after default logic is applied. 
     547   * 
     548   * This method must return false if the buffer has not been parsed. 
     549   * 
     550   * @param string   $buffer           The current route buffer 
     551   * @param array    $tokens           An array of current tokens 
     552   * @param Boolean  $afterASeparator  Whether the buffer is just after a separator 
     553   * @param string   $currentSeparator The last matched separator 
     554   * 
     555   * @return Boolean true if a token has been generated, false otherwise 
     556   */ 
    501557  protected function tokenizeBufferAfter(&$buffer, &$tokens, &$afterASeparator, &$currentSeparator) 
    502558  { 
     
    598654  } 
    599655 
    600   protected function generateStarParameter($url, $defaults, $tparams) 
     656  protected function generateStarParameter($url, $defaults, $parameters) 
    601657  { 
    602658    if (false === strpos($this->regex, '<_star>')) 
     
    606662 
    607663    $tmp = array(); 
    608     foreach (array_diff_key($tparams, $this->variables, $defaults) as $key => $value) 
     664    foreach (array_diff_key($parameters, $this->variables, $defaults) as $key => $value) 
    609665    { 
    610666      if (is_array($value)) 
  • branches/1.2/test/unit/routing/sfRouteTest.php

    r11794 r12969  
    1111require_once(dirname(__FILE__).'/../../bootstrap/unit.php'); 
    1212 
    13 $t = new lime_test(41, new lime_output_color()); 
     13$t = new lime_test(43, new lime_output_color()); 
    1414 
    1515// ->matchesUrl() 
     
    148148$route = new sfRoute('/foo/:foo/*'); 
    149149$t->is($route->generate(array('foo' => 'bar', 'bar' => 'foo')), '/foo/bar/bar/foo', '->generateStarParameter() replaces * with all the key/pair values that are not variables'); 
     150 
     151// custom token 
     152$t->diag('custom token'); 
     153 
     154class MyRoute extends sfRoute 
     155{ 
     156  protected function tokenizeBufferBefore(&$buffer, &$tokens, &$afterASeparator, &$currentSeparator) 
     157  { 
     158    if ($afterASeparator && preg_match('#^=('.$this->options['variable_regex'].')#', $buffer, $match)) 
     159    { 
     160      // a labelled variable 
     161      $this->tokens[] = array('label', $currentSeparator, $match[0], $match[1]); 
     162 
     163      $currentSeparator = ''; 
     164      $buffer = substr($buffer, strlen($match[0])); 
     165      $afterASeparator = false; 
     166    } 
     167    else 
     168    { 
     169      return false; 
     170    } 
     171  } 
     172 
     173  protected function compileForLabel($separator, $name, $variable) 
     174  { 
     175    if (!isset($this->requirements[$variable])) 
     176    { 
     177      $this->requirements[$variable] = $this->options['variable_content_regex']; 
     178    } 
     179 
     180    $this->segments[] = preg_quote($separator, '#').$variable.$separator.'(?P<'.$variable.'>'.$this->requirements[$variable].')'; 
     181    $this->variables[$variable] = $name; 
     182 
     183    if (!isset($this->defaults[$variable])) 
     184    { 
     185      $this->firstOptional = count($this->segments); 
     186    } 
     187  } 
     188 
     189  protected function generateForLabel($optional, $tparams, $separator, $name, $variable) 
     190  { 
     191    if (!empty($tparams[$variable]) && (!$optional || !isset($this->defaults[$variable]) || $tparams[$variable] != $this->defaults[$variable])) 
     192    { 
     193      return $variable . '/' . urlencode($tparams[$variable]); 
     194    } 
     195  } 
     196} 
     197 
     198$route = new MyRoute('/=foo'); 
     199$t->is($route->matchesUrl('/foo/bar'), array('foo' => 'bar'), '->tokenizeBufferBefore() allows to add a custom token'); 
     200$t->is($route->generate(array('foo' => 'bar')), '/foo/bar', '->compileForLabel() adds logic to generate a route for a custom token'); 

The Sensio Labs Network

Since 1998, Sensio Labs has been promoting the Open-Source software movement by providing quality web application development, training, consulting, and supporting several large Open-Source projects.