* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Routing\Generator; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\Exception\InvalidParameterException; use Symfony\Component\Routing\Exception\RouteNotFoundException; use Symfony\Component\Routing\Exception\MissingMandatoryParametersException; /** * UrlGenerator generates URL based on a set of routes. * * @author Fabien Potencier * * @api */ class UrlGenerator implements UrlGeneratorInterface { protected $context; private $routes; private $cache; /** * Constructor. * * @param RouteCollection $routes A RouteCollection instance * @param RequestContext $context The context * * @api */ public function __construct(RouteCollection $routes, RequestContext $context) { $this->routes = $routes; $this->context = $context; $this->cache = array(); } /** * Sets the request context. * * @param RequestContext $context The context * * @api */ public function setContext(RequestContext $context) { $this->context = $context; } /** * Gets the request context. * * @return RequestContext The context */ public function getContext() { return $this->context; } /** * Generates a URL from the given parameters. * * @param string $name The name of the route * @param array $parameters An array of parameters * @param Boolean $absolute Whether to generate an absolute URL * * @return string The generated URL * * @throws Symfony\Component\Routing\Exception\RouteNotFoundException When route doesn't exist * * @api */ public function generate($name, array $parameters = array(), $absolute = false) { if (null === $route = $this->routes->get($name)) { throw new RouteNotFoundException(sprintf('Route "%s" does not exist.', $name)); } if (!isset($this->cache[$name])) { $this->cache[$name] = $route->compile(); } return $this->doGenerate($this->cache[$name]->getVariables(), $route->getDefaults(), $route->getRequirements(), $this->cache[$name]->getTokens(), $parameters, $name, $absolute); } /** * @throws Symfony\Component\Routing\Exception\MissingMandatoryParametersException When route has some missing mandatory parameters * @throws Symfony\Component\Routing\Exception\InvalidParameterException When a parameter value is not correct */ protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $absolute) { $variables = array_flip($variables); $originParameters = $parameters; $parameters = array_replace($this->context->getParameters(), $parameters); $tparams = array_replace($defaults, $parameters); // all params must be given if ($diff = array_diff_key($variables, $tparams)) { throw new MissingMandatoryParametersException(sprintf('The "%s" route has some missing mandatory parameters ("%s").', $name, implode('", "', array_keys($diff)))); } $url = ''; $optional = true; foreach ($tokens as $token) { if ('variable' === $token[0]) { if (false === $optional || !array_key_exists($token[3], $defaults) || (isset($parameters[$token[3]]) && $parameters[$token[3]] != $defaults[$token[3]])) { if (!$isEmpty = in_array($tparams[$token[3]], array(null, '', false), true)) { // check requirement if ($tparams[$token[3]] && !preg_match('#^'.$token[2].'$#', $tparams[$token[3]])) { throw new InvalidParameterException(sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given).', $token[3], $name, $token[2], $tparams[$token[3]])); } } if (!$isEmpty || !$optional) { $url = $token[1].strtr($tparams[$token[3]], array('%'=>'%25', '+'=>'%2B')).$url; } $optional = false; } } elseif ('text' === $token[0]) { $url = $token[1].$url; $optional = false; } } if (!$url) { $url = '/'; } // add a query string if needed if ($extra = array_diff_key($originParameters, $variables, $defaults)) { $url .= '?'.http_build_query($extra); } $url = $this->context->getBaseUrl().$url; if ($this->context->getHost()) { $scheme = $this->context->getScheme(); if (isset($requirements['_scheme']) && ($req = strtolower($requirements['_scheme'])) && $scheme != $req) { $absolute = true; $scheme = $req; } if ($absolute) { $port = ''; if ('http' === $scheme && 80 != $this->context->getHttpPort()) { $port = ':'.$this->context->getHttpPort(); } elseif ('https' === $scheme && 443 != $this->context->getHttpsPort()) { $port = ':'.$this->context->getHttpsPort(); } $url = $scheme.'://'.$this->context->getHost().$port.$url; } } return $url; } }