public function testOtherSpecialChars() { $m = new Horde_Routes_Mapper(); $m->connect('/:year/:(slug).:(format),:(locale)', array('locale' => 'en', 'format' => 'html')); $m->createRegs(array('content')); $this->assertEquals('/2007/test', $m->generate(array('year' => 2007, 'slug' => 'test'))); $this->assertEquals('/2007/test.xml', $m->generate(array('year' => 2007, 'slug' => 'test', 'format' => 'xml'))); $this->assertEquals('/2007/test.xml,ja', $m->generate(array('year' => 2007, 'slug' => 'test', 'format' => 'xml', 'locale' => 'ja'))); $this->assertNull($m->generate(array('year' => 2007, 'format' => 'html'))); }
/** * Generates a URL. * * All keys given to urlFor are sent to the Routes Mapper instance for * generation except for:: * * anchor specified the anchor name to be appened to the path * host overrides the default (current) host if provided * protocol overrides the default (current) protocol if provided * qualified creates the URL with the host/port information as * needed * * The URL is generated based on the rest of the keys. When generating a new * URL, values will be used from the current request's parameters (if * present). The following rules are used to determine when and how to keep * the current requests parameters: * * * If the controller is present and begins with '/', no defaults are used * * If the controller is changed, action is set to 'index' unless otherwise * specified * * For example, if the current request yielded a dict (associative array) of * array('controller'=>'blog', 'action'=>'view', 'id'=>2), with the standard * ':controller/:action/:id' route, you'd get the following results:: * * urlFor(array('id'=>4)) => '/blog/view/4', * urlFor(array('controller'=>'/admin')) => '/admin', * urlFor(array('controller'=>'admin')) => '/admin/view/2' * urlFor(array('action'=>'edit')) => '/blog/edit/2', * urlFor(array('action'=>'list', id=NULL)) => '/blog/list' * * **Static and Named Routes** * * If there is a string present as the first argument, a lookup is done * against the named routes table to see if there's any matching routes. The * keyword defaults used with static routes will be sent in as GET query * arg's if a route matches. * * If no route by that name is found, the string is assumed to be a raw URL. * Should the raw URL begin with ``/`` then appropriate SCRIPT_NAME data will * be added if present, otherwise the string will be used as the url with * keyword args becoming GET query args. */ public function urlFor($first = array(), $second = array()) { if (is_array($first)) { // urlFor(array('controller' => 'foo', ...)) $routeName = null; $kargs = $first; } else { // urlFor('named_route') // urlFor('named_route', array('id' => 3, ...)) // urlFor('static_path') $routeName = $first; $kargs = $second; } $anchor = isset($kargs['anchor']) ? $kargs['anchor'] : null; $host = isset($kargs['host']) ? $kargs['host'] : null; $protocol = isset($kargs['protocol']) ? $kargs['protocol'] : null; $qualified = isset($kargs['qualified']) ? $kargs['qualified'] : null; unset($kargs['qualified']); // Remove special words from kargs, convert placeholders foreach (array('anchor', 'host', 'protocol') as $key) { if (array_key_exists($key, $kargs)) { unset($kargs[$key]); } if (array_key_exists($key . '_', $kargs)) { $kargs[$key] = $kargs[$key . '_']; unset($kargs[$key . '_']); } } $route = null; $static = false; $encoding = $this->mapper->encoding; $environ = $this->mapper->environ; $url = ''; if (isset($routeName)) { if (isset($this->mapper->routeNames[$routeName])) { $route = $this->mapper->routeNames[$routeName]; } if ($route && array_key_exists('_static', $route->defaults)) { $static = true; $url = $route->routePath; } // No named route found, assume the argument is a relative path if ($route === null) { $static = true; $url = $routeName; } if (substr($url, 0, 1) == '/' && isset($environ['SCRIPT_NAME'])) { $url = $environ['SCRIPT_NAME'] . $url; } if ($static) { if (!empty($kargs)) { $url .= '?'; $query_args = array(); foreach ($kargs as $key => $val) { $query_args[] = urlencode(utf8_decode($key)) . '=' . urlencode(utf8_decode($val)); } $url .= implode('&', $query_args); } } } if (!$static) { if ($route) { $newargs = $route->defaults; foreach ($kargs as $key => $value) { $newargs[$key] = $value; } // If this route has a filter, apply it if (!empty($route->filter)) { $newargs = call_user_func($route->filter, $newargs); } $newargs = $this->_subdomainCheck($newargs); } else { $newargs = $this->_screenArgs($kargs); } $anchor = isset($newargs['_anchor']) ? $newargs['_anchor'] : $anchor; unset($newargs['_anchor']); $host = isset($newargs['_host']) ? $newargs['_host'] : $host; unset($newargs['_host']); $protocol = isset($newargs['_protocol']) ? $newargs['_protocol'] : $protocol; unset($newargs['_protocol']); $url = $this->mapper->generate($newargs); } if (!empty($anchor)) { $url .= '#' . self::urlQuote($anchor, $encoding); } if (!empty($host) || !empty($qualified) || !empty($protocol)) { $http_host = isset($environ['HTTP_HOST']) ? $environ['HTTP_HOST'] : null; $server_name = isset($environ['SERVER_NAME']) ? $environ['SERVER_NAME'] : null; $fullhost = !is_null($http_host) ? $http_host : $server_name; if (empty($host) && empty($qualified)) { $host = explode(':', $fullhost); $host = $host[0]; } else { if (empty($host)) { $host = $fullhost; } } if (empty($protocol)) { if (!empty($environ['HTTPS']) && $environ['HTTPS'] != 'off') { $protocol = 'https'; } else { $protocol = 'http'; } } if ($url !== null) { $url = $protocol . '://' . $host . $url; } } return $url; }