Development

Changeset 11471

You must first sign up to be able to contribute.

Changeset 11471

Show
Ignore:
Timestamp:
09/12/08 12:03:49 (5 years ago)
Author:
fabien
Message:

[1.2] added a lot of REST goodness to symfony 1.2 (live from symfony camp)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/1.2/UPGRADE_TO_1_2

    r11452 r11471  
    2626 
    2727The remaining sections explain the main changes made in symfony 1.2. 
    28  
    2928 
    3029Propel 
     
    786785task name is still available as an alias. 
    787786 
     787The `non-atomic-actions` option of `propel:generate-module` has been removed 
     788and some new options have been added: 
     789 
     790  * singular:          The singular name for the actions and templates 
     791  * plural:            The plural name for the actions and templates 
     792  * route-prefix:      The route prefix to use 
     793  * with-propel-route: Whether the related routes are Propel aware 
     794 
     795The new `propel:generate-module-for-route` generates a module based on a route 
     796definition: 
     797 
     798    [php] 
     799    php symfony propel:generate-module-for-route frontend articles 
     800 
     801As symfony now can auto-generate routes (see below), the `app:routes` task 
     802displays the list of current routes for an application: 
     803 
     804    [php] 
     805    php symfony app:routes frontend 
     806 
     807If you want to get some details about a route, just add the route name: 
     808 
     809    [php] 
     810    php symfony app:routes frontend articles_update 
     811 
    788812Routing 
    789813------- 
     
    899923    // /articles?page=2 
    900924 
     925symfony 1.2 comes with another route class that extends `sfRequestRoute`, 
     926`sfObjectRoute`. 
     927 
     928`sfObjectRoute` binds a route to a PHP object. A `sfObjectRoute` will 
     929call some methods on your PHP class to get the object, or a collection of 
     930objects, related to the route. 
     931 
     932The object or the collection of objects will be available in your actions 
     933via a request attribute: 
     934 
     935   [yml] 
     936   article: 
     937     url:     /article/:id 
     938     class:   sfObjectRoute 
     939     options: { model: Article, object: article, method: getById } 
     940 
     941When an incoming URL matches the route, the `sfObjectRoute` will get the 
     942related object by calling the `Article::getById()` method and will inject 
     943the result into the request attributes (under the `article` key). 
     944 
     945The same goes for a collection of objects: 
     946 
     947    [yml] 
     948    articles: 
     949      url:     /articles/newest 
     950      class:   sfObjectRoute 
     951      options: { model: Article, list: articles, method: getNewest } 
     952 
     953`sfPropelRoute` extends `sfObjectRoute` to bind a route to a Propel model. 
     954 
     955Here is an example for an `Article` Propel object: 
     956 
     957    [yml] 
     958    article: 
     959      url:     /article/:id 
     960      param:   { module: article, action: show } 
     961      class:   sfPropelRoute 
     962      options: { model: Article, object: article } 
     963 
     964    articles: 
     965      url:     /articles 
     966      param:   { module: article, action: list } 
     967      class:   sfPropelRoute 
     968      options: { model: Article, list: articles, method: getPublishedArticleCriteria } 
     969 
     970If you don't define a method, `sfPropelRoute` will retrieve the object 
     971by building a Criteria object based on the available route variables. 
     972 
     973The `sfPropelRoute` has two main advantages over `sfRoute`: 
     974 
     975  * When a request comes in and the route matches the URL, `sfPropelRoute` 
     976    will automatically inject the related `Article` object with a name of `article`. 
     977    Moreover, if the object does not exist in the database, it will automatically 
     978    redirect the user to a 404 error page. This means less boiler-plate code in 
     979    your actions. 
     980 
     981  * When you generate a link for this route, you can use the new `url_for()` 
     982    signature and pass the article object directly for the parameters argument: 
     983 
     984        [php] 
     985        <?php echo url_for('article', $article) ?> 
     986 
     987    If you have to pass extra parameters (to enforce a HTTP method for example), 
     988    you can use an array like this: 
     989 
     990        [php] 
     991        <?php echo url_for('article', array('sf_subject' => $article, 'sf_method' => 'get')) ?> 
     992 
     993    And of course, you can still use the full parameters: 
     994 
     995        [php] 
     996        <?php echo url_for('article', array('id' => $article->getId(), 'slug' => $article->getSlug())) ?> 
     997 
     998    Or use the internal URI: 
     999 
     1000        <?php echo url_for('@article?id='.$article->getId().'&slug='.$article->getSlug()) ?> 
     1001 
     1002    The `sfPropelRoute` converts the article object to an array of parameters automatically. 
     1003 
     1004`sfPropelRoute` does not only work with the primary key. It can also work with 
     1005any column. In the following example, let's add the `slug` column to the route 
     1006pattern: 
     1007 
     1008    [yml] 
     1009    article: 
     1010      url:     /article/:id/:slug 
     1011      param:   { module: article, action: show } 
     1012      class:   sfPropelRoute 
     1013      options: { model: Article, object: article } 
     1014 
     1015But sometimes, you want to put in the pattern some information that does not 
     1016exist in the database. In this case, you can pass a `method` option: 
     1017 
     1018    [yml] 
     1019    post: 
     1020      url:     /post/:id/:year/:month/:day/:slug 
     1021      param:   { module: article, action: show } 
     1022      class:   sfPropelRoute 
     1023      options: { model: Article, object: article, method: getObjectForRoute } 
     1024 
     1025The `getObjectForRoute()` receives an array of parameters as its first 
     1026argument and must return an `Article` object: 
     1027 
     1028    [php] 
     1029    class ArticlePeer extends BaseArticlePeer 
     1030    { 
     1031      static public function getObjectForRoute($parameters) 
     1032      { 
     1033        $criteria = new Criteria(); 
     1034        $criteria->add(self::ID, $parameters['id']); 
     1035 
     1036        return self::doSelectOne($criteria); 
     1037      } 
     1038    } 
     1039 
    9011040URL helpers 
    9021041----------- 
     
    9171056    // and equivalent to 
    9181057    <?php echo link_to('@some_route', array('method' => 'post')) ?> 
     1058 
     1059The `url_for()` and `link_to()` helpers support new signatures. 
     1060Instead of an internal URI, they can now also take the route name and 
     1061an array of parameters: 
     1062 
     1063    [php] 
     1064    echo url_for('@article', array('id' => 1)); 
     1065    echo link_to('Link to article', '@article', array('id' => 1)); 
     1066 
     1067The old behavior still works without changing anything to your code. 
  • branches/1.2/lib/autoload/sfCoreAutoload.class.php

    r11406 r11471  
    296296  'sfWebResponse' => 'response', 
    297297  'sfNoRouting' => 'routing', 
     298  'sfObjectRoute' => 'routing', 
     299  'sfObjectRouteCollection' => 'routing', 
    298300  'sfPathInfoRouting' => 'routing', 
    299301  'sfPatternRouting' => 'routing', 
    300302  'sfRequestRoute' => 'routing', 
    301303  'sfRoute' => 'routing', 
     304  'sfRouteCollection' => 'routing', 
    302305  'sfRouting' => 'routing', 
    303306  'sfDatabaseSessionStorage' => 'storage', 
     
    310313  'sfSessionTestStorage' => 'storage', 
    311314  'sfStorage' => 'storage', 
     315  'sfAppRoutesTask' => 'task/app', 
    312316  'sfCacheClearTask' => 'task/cache', 
    313317  'sfConfigureAuthorTask' => 'task/configure', 
  • branches/1.2/lib/config/sfRoutingConfigHandler.class.php

    r11313 r11471  
    2929  public function execute($configFiles) 
    3030  { 
    31     // parse the yaml 
    32     $config = self::getConfiguration($configFiles); 
     31    $routes = $this->parseConfiguration($configFiles); 
    3332 
    34     // connect routes 
    3533    $data = array(); 
    36     foreach ($config as $name => $params
     34    foreach ($routes as $name => $route
    3735    { 
    38       $parameters = isset($params['params']) ? $params['params'] : (isset($params['param']) ? $params['param'] : array()); 
     36      $arguments = array(); 
     37      foreach ($route[1] as $argument) 
     38      { 
     39        $arguments[] = is_array($argument) ? var_export($argument, true) : sprintf("'%s'", $argument); 
     40      } 
    3941 
    40       $data[] = sprintf('\'%s\' => new %s(\'%s\', %s, %s, %s),', 
    41         $name, 
    42         isset($params['class']) ? $params['class'] : 'sfRoute', 
    43         $params['url'] ? $params['url'] : '/', 
    44         var_export($parameters, true), 
    45         isset($params['requirements']) ? var_export($params['requirements'], true) : 'array()', 
    46         isset($params['options']) ? var_export($params['options'], true) : 'array()' 
    47       ); 
     42      $data[] = sprintf('\'%s\' => new %s(%s),', $name, $route[0], implode(', ', $arguments)); 
    4843    } 
    4944 
     
    5247                   "// date: %s\nreturn array(\n%s\n);\n", date('Y/m/d H:i:s'), implode("\n", $data) 
    5348    ); 
     49  } 
     50 
     51  public function evaluate($configFiles) 
     52  { 
     53    $routeDefinitions = $this->parseConfiguration($configFiles); 
     54 
     55    $routes = array(); 
     56    foreach ($routeDefinitions as $name => $route) 
     57    { 
     58      $arguments = array(); 
     59      foreach ($route[1] as $argument) 
     60      { 
     61        $arguments[] = is_array($argument) ? var_export($argument, true) : sprintf("'%s'", $argument); 
     62      } 
     63 
     64      $r = new ReflectionClass($route[0]); 
     65      $routes[$name] = $r->newInstanceArgs($route[1]); 
     66    } 
     67 
     68    return $routes; 
     69  } 
     70 
     71  protected function parseConfiguration($configFiles) 
     72  { 
     73    // parse the yaml 
     74    $config = self::getConfiguration($configFiles); 
     75 
     76    // collect routes 
     77    $routes = array(); 
     78    foreach ($config as $name => $params) 
     79    { 
     80      if ( 
     81        (isset($params['type']) && 'collection' == $params['type']) 
     82        || 
     83        (isset($params['class']) && false !== strpos($params['class'], 'Collection')) 
     84      ) 
     85      { 
     86        $options = isset($params['options']) ? $params['options'] : array(); 
     87        $options['name'] = $name; 
     88        $options['requirements'] = isset($params['requirements']) ? $params['requirements'] : array(); 
     89 
     90        $routes[$name] = array(isset($params['class']) ? $params['class'] : 'sfRouteCollection', array($options)); 
     91      } 
     92      else 
     93      { 
     94        $routes[$name] = array(isset($params['class']) ? $params['class'] : 'sfRoute', array( 
     95          $params['url'] ? $params['url'] : '/', 
     96          isset($params['params']) ? $params['params'] : (isset($params['param']) ? $params['param'] : array()), 
     97          isset($params['requirements']) ? $params['requirements'] : array(), 
     98          isset($params['options']) ? $params['options'] : array(), 
     99        )); 
     100      } 
     101    } 
     102 
     103    return $routes; 
    54104  } 
    55105 
  • branches/1.2/lib/controller/sfWebController.class.php

    r11313 r11471  
    8787    $givenUrl = $url; 
    8888 
    89     $params       = array(); 
    90     $query_string = ''; 
    91     $route   = ''; 
     89    $params = array(); 
     90    $queryString = ''; 
     91    $route = ''; 
    9292 
    9393    // empty url? 
     
    100100    if ($pos = strpos($url, '?')) 
    101101    { 
    102       $query_string = substr($url, $pos + 1); 
     102      $queryString = substr($url, $pos + 1); 
    103103      $url = substr($url, 0, $pos); 
    104104    } 
     
    124124      list($params['module'], $params['action']) = explode('/', $url); 
    125125    } 
     126    else if (!$queryString) 
     127    { 
     128      $route = $givenUrl; 
     129    } 
    126130    else 
    127131    { 
     
    130134 
    131135    // split the query string 
    132     if ($query_string) 
     136    if ($queryString) 
    133137    { 
    134138      $matched = preg_match_all('/ 
     
    139143          (?=&[^&=]+=) | $  # followed by another key= or the end of the string 
    140144        ) 
    141       /x', $query_string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE); 
     145      /x', $queryString, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE); 
    142146      foreach ($matches as $match) 
    143147      { 
     
    148152      if (!$matched) 
    149153      { 
    150         throw new sfParseException(sprintf('Unable to parse query string "%s".', $query_string)); 
     154        throw new sfParseException(sprintf('Unable to parse query string "%s".', $queryString)); 
    151155      } 
    152156    } 
  • branches/1.2/lib/exception/sfError404Exception.class.php

    r6975 r11471  
    2626    $exception = is_null($this->wrappedException) ? $this : $this->wrappedException; 
    2727 
    28     if (sfConfig::get('sf_debug')
     28    if (sfConfig::get('sf_debug') && !sfConfig::get('sf_test')
    2929    { 
    3030      $response = sfContext::getInstance()->getResponse(); 
  • branches/1.2/lib/generator/sfCrudGenerator.class.php

    r11349 r11471  
    260260   * @return string PHP code 
    261261   */ 
    262   public function getPrimaryKeyUrlParams($prefix = ''
     262  public function getPrimaryKeyUrlParams($prefix = '', $full = false
    263263  { 
    264264    $params = array(); 
     
    267267      $phpName   = $pk->getPhpName(); 
    268268      $fieldName = sfInflector::underscore($phpName); 
    269       $params[]  = "$fieldName='.".$this->getColumnGetter($pk, true, $prefix); 
     269      if ($full) 
     270      { 
     271        $params[]  = "$fieldName='.".$prefix.'->'.$this->getColumnGetter($pk, false).'()'; 
     272      } 
     273      else 
     274      { 
     275        $params[]  = "$fieldName='.".$this->getColumnGetter($pk, true, $prefix); 
     276      } 
    270277    } 
    271278 
  • branches/1.2/lib/helper/UrlHelper.php

    r11344 r11471  
    1818 */ 
    1919 
     20function link_to2($name, $routeName, $params, $options = array()) 
     21{ 
     22  $params = array_merge(array('sf_route' => $routeName), is_object($params) ? array('sf_subject' => $params) : $params); 
     23 
     24  return link_to1($name, $params, $options); 
     25} 
     26 
     27function link_to1($name, $internal_uri, $options = array()) 
     28{ 
     29  $html_options = _parse_attributes($options); 
     30 
     31  $html_options = _convert_options_to_javascript($html_options); 
     32 
     33  $absolute = false; 
     34  if (isset($html_options['absolute_url'])) 
     35  { 
     36    $html_options['absolute'] = $html_options['absolute_url']; 
     37    unset($html_options['absolute_url']); 
     38  } 
     39  if (isset($html_options['absolute'])) 
     40  { 
     41    $absolute = (boolean) $html_options['absolute']; 
     42    unset($html_options['absolute']); 
     43  } 
     44 
     45  $html_options['href'] = url_for($internal_uri, $absolute); 
     46 
     47  if (isset($html_options['query_string'])) 
     48  { 
     49    $html_options['href'] .= '?'.$html_options['query_string']; 
     50    unset($html_options['query_string']); 
     51  } 
     52 
     53  if (isset($html_options['anchor'])) 
     54  { 
     55    $html_options['href'] .= '#'.$html_options['anchor']; 
     56    unset($html_options['anchor']); 
     57  } 
     58 
     59  if (is_object($name)) 
     60  { 
     61    if (method_exists($name, '__toString')) 
     62    { 
     63      $name = $name->__toString(); 
     64    } 
     65    else 
     66    { 
     67      throw new sfException(sprintf('Object of class "%s" cannot be converted to string (Please create a __toString() method).', get_class($name))); 
     68    } 
     69  } 
     70 
     71  if (!strlen($name)) 
     72  { 
     73    $name = $html_options['href']; 
     74  } 
     75 
     76  return content_tag('a', $name, $html_options); 
     77} 
     78 
     79function url_for2($routeName, $params = array(), $absolute = false) 
     80{ 
     81  $params = array_merge(array('sf_route' => $routeName), is_object($params) ? array('sf_subject' => $params) : $params); 
     82 
     83  return url_for1($params, $absolute); 
     84} 
     85 
     86function url_for1($internal_uri, $absolute = false) 
     87{ 
     88  return sfContext::getInstance()->getController()->genUrl($internal_uri, $absolute); 
     89} 
    2090 
    2191/** 
     
    37107 * @return string routed URL 
    38108 */ 
    39 function url_for($internal_uri, $absolute = false) 
    40 
    41   return sfContext::getInstance()->getController()->genUrl($internal_uri, $absolute); 
     109function url_for() 
     110
     111  // for BC with 1.1 
     112  $arguments = func_get_args(); 
     113  if (is_array($arguments[0]) || '@' == substr($arguments[0], 0, 1) || false !== strpos($arguments[0], '/')) 
     114  { 
     115    return call_user_func_array('url_for1', $arguments); 
     116  } 
     117  else 
     118  { 
     119    return call_user_func_array('url_for2', $arguments); 
     120  } 
    42121} 
    43122 
     
    81160 * @see    url_for 
    82161 */ 
    83 function link_to($name = '', $internal_uri = '', $options = array()) 
    84 
    85   $html_options = _parse_attributes($options); 
    86  
    87   $html_options = _convert_options_to_javascript($html_options); 
    88  
    89   $absolute = false; 
    90   if (isset($html_options['absolute_url'])) 
    91   { 
    92     $html_options['absolute'] = $html_options['absolute_url']; 
    93     unset($html_options['absolute_url']); 
    94   } 
    95   if (isset($html_options['absolute'])) 
    96   { 
    97     $absolute = (boolean) $html_options['absolute']; 
    98     unset($html_options['absolute']); 
    99   } 
    100  
    101   $html_options['href'] = url_for($internal_uri, $absolute); 
    102  
    103   if (isset($html_options['query_string'])) 
    104   { 
    105     $html_options['href'] .= '?'.$html_options['query_string']; 
    106     unset($html_options['query_string']); 
    107   } 
    108  
    109   if (isset($html_options['anchor'])) 
    110   { 
    111     $html_options['href'] .= '#'.$html_options['anchor']; 
    112     unset($html_options['anchor']); 
    113   } 
    114  
    115   if (is_object($name)) 
    116   { 
    117     if (method_exists($name, '__toString')) 
    118     { 
    119       $name = $name->__toString(); 
    120     } 
    121     else 
    122     { 
    123       throw new sfException(sprintf('Object of class "%s" cannot be converted to string (Please create a __toString() method).', get_class($name))); 
    124     } 
    125   } 
    126  
    127   if (!strlen($name)) 
    128   { 
    129     $name = $html_options['href']; 
    130   } 
    131  
    132   return content_tag('a', $name, $html_options); 
     162function link_to() 
     163
     164  // for BC with 1.1 
     165  $arguments = func_get_args(); 
     166  if (empty($arguments[1]) || '@' == substr($arguments[1], 0, 1) || false !== strpos($arguments[1], '/')) 
     167  { 
     168    return call_user_func_array('link_to1', $arguments); 
     169  } 
     170  else 
     171  { 
     172    return call_user_func_array('link_to2', $arguments); 
     173  } 
     174
     175 
     176function url_for_form(sfForm $form, $routePrefix) 
     177
     178  $format = '%s/%s'; 
     179  if ('@' == $routePrefix[0]) 
     180  { 
     181    $format = '%s_%s'; 
     182    $routePrefix = substr($routePrefix, 1); 
     183  } 
     184 
     185  $uri = sprintf($format, $routePrefix, $form->getObject()->isNew() ? 'create' : 'update'); 
     186 
     187  return url_for($uri, $form->getObject()); 
     188
     189 
     190function form_tag_for(sfForm $form, $routePrefix) 
     191
     192  return $form->renderFormTag(url_for_form($form, $routePrefix)); 
    133193} 
    134194 
     
    277337 * @see    url_for, link_to 
    278338 */ 
    279 function button_to($name, $internal_uri ='', $options = array()) 
     339function button_to($name, $internal_uri, $options = array()) 
    280340{ 
    281341  $html_options = _parse_attributes($options); 
  • branches/1.2/lib/routing/sfPatternRouting.class.php

    r11348 r11471  
    244244    } 
    245245 
    246     $this->routes[$name] = $route; 
    247     $this->configureRoute($route); 
    248  
    249     if ($this->options['logging']) 
    250     { 
    251       $this->dispatcher->notify(new sfEvent($this, 'application.log', array(sprintf('Connect %s "%s" (%s)', get_class($route), $name, $route->getPattern())))); 
     246    $routes = $route instanceof sfRouteCollection ? $route : array($name => $route); 
     247    foreach (self::flattenRoutes($routes) as $name => $route) 
     248    { 
     249      $this->routes[$name] = $route; 
     250      $this->configureRoute($route); 
     251 
     252      if ($this->options['logging']) 
     253      { 
     254        $this->dispatcher->notify(new sfEvent($this, 'application.log', array(sprintf('Connect %s "%s" (%s)', get_class($route), $name, $route->getPattern())))); 
     255      } 
    252256    } 
    253257 
     
    422426  } 
    423427 
     428  static public function flattenRoutes($routes) 
     429  { 
     430    $flattenRoutes = array(); 
     431    foreach ($routes as $name => $route) 
     432    { 
     433      if ($route instanceof sfRouteCollection) 
     434      { 
     435        $flattenRoutes = array_merge($flattenRoutes, self::flattenRoutes($route)); 
     436      } 
     437      else 
     438      { 
     439        $flattenRoutes[$name] = $route; 
     440      } 
     441    } 
     442 
     443    return $flattenRoutes; 
     444  } 
     445 
    424446  protected function getRouteThatMatchesUrl($url) 
    425447  { 
  • branches/1.2/lib/routing/sfRouting.class.php

    r11427 r11471  
    242242  { 
    243243    $context = $event->getParameters(); 
    244     unset($context['path_info']); 
    245244 
    246245    $this->options['context'] = $context; 
  • branches/1.2/test/unit/helper/UrlHelperTest.php

    r10188 r11471  
    4848// url_for() 
    4949$t->diag('url_for()'); 
    50 $t->is(url_for('test'), 'module/action', 'url_for() converts an internal URI to a web URI'); 
    51 $t->is(url_for('test', true), '/module/action', 'url_for() can take an absolute boolean as its second argument'); 
    52 $t->is(url_for('test', false), 'module/action', 'url_for() can take an absolute boolean as its second argument'); 
     50$t->is(url_for('@test'), 'module/action', 'url_for() converts an internal URI to a web URI'); 
     51$t->is(url_for('@test', true), '/module/action', 'url_for() can take an absolute boolean as its second argument'); 
     52$t->is(url_for('@test', false), 'module/action', 'url_for() can take an absolute boolean as its second argument'); 
    5353 
    5454// link_to() 
    5555$t->diag('link_to()'); 
    56 $t->is(link_to('test'), '<a href="module/action">test</a>', 'link_to() returns an HTML "a" tag'); 
    57 $t->is(link_to('test', '', array('absolute' => true)), '<a href="/module/action">test</a>', 'link_to() can take an "absolute" option'); 
    58 $t->is(link_to('test', '', array('absolute' => false)), '<a href="module/action">test</a>', 'link_to() can take an "absolute" option'); 
    59 $t->is(link_to('test', '', array('query_string' => 'foo=bar')), '<a href="module/action?foo=bar">test</a>', 'link_to() can take a "query_string" option'); 
    60 $t->is(link_to('test', '', array('anchor' => 'bar')), '<a href="module/action#bar">test</a>', 'link_to() can take an "anchor" option'); 
    61 $t->is(link_to(''), '<a href="module/action">module/action</a>', 'link_to() takes the url as the link name if the first argument is empty'); 
     56$t->is(link_to('test', '@homepage'), '<a href="module/action">test</a>', 'link_to() returns an HTML "a" tag'); 
     57$t->is(link_to('test', '@homepage', array('absolute' => true)), '<a href="/module/action">test</a>', 'link_to() can take an "absolute" option'); 
     58$t->is(link_to('test', '@homepage', array('absolute' => false)), '<a href="module/action">test</a>', 'link_to() can take an "absolute" option'); 
     59$t->is(link_to('test', '@homepage', array('query_string' => 'foo=bar')), '<a href="module/action?foo=bar">test</a>', 'link_to() can take a "query_string" option'); 
     60$t->is(link_to('test', '@homepage', array('anchor' => 'bar')), '<a href="module/action#bar">test</a>', 'link_to() can take an "anchor" option'); 
     61$t->is(link_to('', '@homepage'), '<a href="module/action">module/action</a>', 'link_to() takes the url as the link name if the first argument is empty'); 
    6262 
    63 //button_to() 
     63// button_to() 
    6464$t->diag('button_to()'); 
    65 $t->is(button_to('test'), '<input value="test" type="button" onclick="document.location.href=\'module/action\';" />', 'button_to() returns an HTML "input" tag'); 
    66 $t->is(button_to('test','', array('query_string' => 'foo=bar')), '<input value="test" type="button" onclick="document.location.href=\'module/action?foo=bar\';" />', 'button_to() returns an HTML "input" tag'); 
    67 $t->is(button_to('test','', array('anchor' => 'bar')), '<input value="test" type="button" onclick="document.location.href=\'module/action#bar\';" />', 'button_to() returns an HTML "input" tag'); 
    68 $t->is(button_to('test','', array('popup' => 'true', 'query_string' => 'foo=bar')), '<input value="test" type="button" onclick="var w=window.open(\'module/action?foo=bar\');w.focus();return false;" />', 'button_to() returns an HTML "input" tag'); 
    69 $t->is(button_to('test','', 'popup=true'), '<input value="test" type="button" onclick="var w=window.open(\'module/action\');w.focus();return false;" />', 'button_to() accepts options as string'); 
    70 $t->is(button_to('test','', 'confirm=really?'), '<input value="test" type="button" onclick="if (confirm(\'really?\')) { return document.location.href=\'module/action\';} else return false;" />', 'button_to() works with confirm option'); 
    71 $t->is(button_to('test','', 'popup=true confirm=really?'), '<input value="test" type="button" onclick="if (confirm(\'really?\')) { var w=window.open(\'module/action\');w.focus(); };return false;" />', 'button_to() works with confirm and popup option'); 
     65$t->is(button_to('test', '@homepage'), '<input value="test" type="button" onclick="document.location.href=\'module/action\';" />', 'button_to() returns an HTML "input" tag'); 
     66$t->is(button_to('test', '@homepage', array('query_string' => 'foo=bar')), '<input value="test" type="button" onclick="document.location.href=\'module/action?foo=bar\';" />', 'button_to() returns an HTML "input" tag'); 
     67$t->is(button_to('test', '@homepage', array('anchor' => 'bar')), '<input value="test" type="button" onclick="document.location.href=\'module/action#bar\';" />', 'button_to() returns an HTML "input" tag'); 
     68$t->is(button_to('test', '@homepage', array('popup' => 'true', 'query_string' => 'foo=bar')), '<input value="test" type="button" onclick="var w=window.open(\'module/action?foo=bar\');w.focus();return false;" />', 'button_to() returns an HTML "input" tag'); 
     69$t->is(button_to('test', '@homepage', 'popup=true'), '<input value="test" type="button" onclick="var w=window.open(\'module/action\');w.focus();return false;" />', 'button_to() accepts options as string'); 
     70$t->is(button_to('test', '@homepage', 'confirm=really?'), '<input value="test" type="button" onclick="if (confirm(\'really?\')) { return document.location.href=\'module/action\';} else return false;" />', 'button_to() works with confirm option'); 
     71$t->is(button_to('test', '@homepage', 'popup=true confirm=really?'), '<input value="test" type="button" onclick="if (confirm(\'really?\')) { var w=window.open(\'module/action\');w.focus(); };return false;" />', 'button_to() works with confirm and popup option'); 
    7272 
    7373class testObject 
    7474{ 
    7575} 
     76 
    7677try 
    7778{ 
    7879  $o1 = new testObject(); 
    79   link_to($o1); 
     80  link_to($o1, '@homepage'); 
    8081  $t->fail('link_to() can take an object as its first argument if __toString() method is defined'); 
    8182} 
     
    9394} 
    9495$o2 = new testObjectWithToString(); 
    95 $t->is(link_to($o2), '<a href="module/action">test</a>', 'link_to() can take an object as its first argument'); 
     96$t->is(link_to($o2, '@homepage'), '<a href="module/action">test</a>', 'link_to() can take an object as its first argument'); 
    9697 
    9798// link_to_if() 
    9899$t->diag('link_to_if()'); 
    99 $t->is(link_to_if(true, 'test', ''), '<a href="module/action">test</a>', 'link_to_if() returns an HTML "a" tag if the condition is true'); 
    100 $t->is(link_to_if(false, 'test', ''), '<span>test</span>', 'link_to_if() returns an HTML "span" tag by default if the condition is false'); 
    101 $t->is(link_to_if(false, 'test', '', array('tag' => 'div')), '<div>test</div>', 'link_to_if() takes a "tag" option'); 
    102 $t->is(link_to_if(true, 'test', '', 'tag=div'), '<a href="module/action">test</a>', 'link_to_if() removes "tag" option (given as string) in true case'); 
    103 $t->is(link_to_if(true, 'test', '', array('tag' => 'div')), '<a href="module/action">test</a>', 'link_to_if() removes "tag" option (given as array) in true case'); 
    104 $t->is(link_to_if(false, 'test', '', array('query_string' => 'foo=bar', 'absolute' => true, 'absolute_url' => 'http://www.google.com/')), '<span>test</span>', 'link_to_if() returns an HTML "span" tag by default if the condition is false'); 
     100$t->is(link_to_if(true, 'test', '@homepage'), '<a href="module/action">test</a>', 'link_to_if() returns an HTML "a" tag if the condition is true'); 
     101$t->is(link_to_if(false, 'test', '@homepage'), '<span>test</span>', 'link_to_if() returns an HTML "span" tag by default if the condition is false'); 
     102$t->is(link_to_if(false, 'test', '@homepage', array('tag' => 'div')), '<div>test</div>', 'link_to_if() takes a "tag" option'); 
     103$t->is(link_to_if(true, 'test', '@homepage', 'tag=div'), '<a href="module/action">test</a>', 'link_to_if() removes "tag" option (given as string) in true case'); 
     104$t->is(link_to_if(true, 'test', '@homepage', array('tag' => 'div')), '<a href="module/action">test</a>', 'link_to_if() removes "tag" option (given as array) in true case'); 
     105$t->is(link_to_if(false, 'test', '@homepage', array('query_string' => 'foo=bar', 'absolute' => true, 'absolute_url' => 'http://www.google.com/')), '<span>test</span>', 'link_to_if() returns an HTML "span" tag by default if the condition is false'); 
    105106 
    106107// link_to_unless() 
    107108$t->diag('link_to_unless()'); 
    108 $t->is(link_to_unless(false, 'test', ''), '<a href="module/action">test</a>', 'link_to_unless() returns an HTML "a" tag if the condition is false'); 
    109 $t->is(link_to_unless(true, 'test', ''), '<span>test</span>', 'link_to_unless() returns an HTML "span" tag by default if the condition is true'); 
     109$t->is(link_to_unless(false, 'test', '@homepage'), '<a href="module/action">test</a>', 'link_to_unless() returns an HTML "a" tag if the condition is false'); 
     110$t->is(link_to_unless(true, 'test', '@homepage'), '<span>test</span>', 'link_to_unless() returns an HTML "span" tag by default if the condition is true'); 
    110111 
    111112// public_path()