-
Notifications
You must be signed in to change notification settings - Fork 11.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0f3e509
commit 39e8c83
Showing
3 changed files
with
428 additions
and
345 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,318 @@ | ||
<?php | ||
|
||
namespace Illuminate\Routing; | ||
|
||
use Illuminate\Support\Arr; | ||
use Illuminate\Support\Str; | ||
use Illuminate\Routing\Exceptions\UrlGenerationException; | ||
|
||
class RouteUrlGenerator | ||
{ | ||
/** | ||
* The URL generator instance. | ||
* | ||
* @param \Illuminate\Routing\UrlGenerator | ||
*/ | ||
protected $url; | ||
|
||
/** | ||
* The request instance. | ||
* | ||
* @var \Illuminate\Http\Request | ||
*/ | ||
protected $request; | ||
|
||
/** | ||
* The named parameter defaults. | ||
* | ||
* @var array | ||
*/ | ||
public $defaultParameters = []; | ||
|
||
/** | ||
* Characters that should not be URL encoded. | ||
* | ||
* @var array | ||
*/ | ||
public $dontEncode = [ | ||
'%2F' => '/', | ||
'%40' => '@', | ||
'%3A' => ':', | ||
'%3B' => ';', | ||
'%2C' => ',', | ||
'%3D' => '=', | ||
'%2B' => '+', | ||
'%21' => '!', | ||
'%2A' => '*', | ||
'%7C' => '|', | ||
'%3F' => '?', | ||
'%26' => '&', | ||
'%23' => '#', | ||
'%25' => '%', | ||
]; | ||
|
||
/** | ||
* Create a new Route URL generator. | ||
* | ||
* @param \Illuminate\Routing\UrlGenerator $url | ||
* @param \Illuminate\Http\Request $request | ||
* @return void | ||
*/ | ||
public function __construct($url, $request) | ||
{ | ||
$this->url = $url; | ||
$this->request = $request; | ||
} | ||
|
||
/** | ||
* Generate a URL for the given route. | ||
* | ||
* @param \Illuminate\Routing\UrlGeneartor $url | ||
* @param \Illuminate\Routing\Route $route | ||
* @param array $parameters | ||
* @param bool $absolute | ||
* @return string | ||
*/ | ||
public function to($route, $parameters = [], $absolute = false) | ||
{ | ||
$domain = $this->getRouteDomain($route, $parameters); | ||
|
||
$uri = $this->addQueryString($this->url->format( | ||
$root = $this->replaceRoot($route, $domain, $parameters), | ||
$this->replaceRouteParameters($route->uri(), $parameters) | ||
), $parameters); | ||
|
||
if (preg_match('/\{.*?\}/', $uri)) { | ||
throw UrlGenerationException::forMissingParameters($route); | ||
} | ||
|
||
$uri = strtr(rawurlencode($uri), $this->dontEncode); | ||
|
||
return $absolute ? $uri : '/'.ltrim(str_replace($root, '', $uri), '/'); | ||
} | ||
|
||
/** | ||
* Get the formatted domain for a given route. | ||
* | ||
* @param \Illuminate\Routing\Route $route | ||
* @param array $parameters | ||
* @return string | ||
*/ | ||
protected function getRouteDomain($route, &$parameters) | ||
{ | ||
return $route->domain() ? $this->formatDomain($route, $parameters) : null; | ||
} | ||
|
||
/** | ||
* Format the domain and port for the route and request. | ||
* | ||
* @param \Illuminate\Routing\Route $route | ||
* @param array $parameters | ||
* @return string | ||
*/ | ||
protected function formatDomain($route, &$parameters) | ||
{ | ||
return $this->addPortToDomain($this->getDomainAndScheme($route)); | ||
} | ||
|
||
/** | ||
* Get the domain and scheme for the route. | ||
* | ||
* @param \Illuminate\Routing\Route $route | ||
* @return string | ||
*/ | ||
protected function getDomainAndScheme($route) | ||
{ | ||
return $this->getRouteScheme($route).$route->domain(); | ||
} | ||
|
||
/** | ||
* Get the scheme for the given route. | ||
* | ||
* @param \Illuminate\Routing\Route $route | ||
* @return string | ||
*/ | ||
protected function getRouteScheme($route) | ||
{ | ||
if ($route->httpOnly()) { | ||
return 'http://'; | ||
} elseif ($route->httpsOnly()) { | ||
return 'https://'; | ||
} | ||
|
||
return $this->url->formatScheme(null); | ||
} | ||
|
||
/** | ||
* Add the port to the domain if necessary. | ||
* | ||
* @param string $domain | ||
* @return string | ||
*/ | ||
protected function addPortToDomain($domain) | ||
{ | ||
$secure = $this->request->isSecure(); | ||
|
||
$port = (int) $this->request->getPort(); | ||
|
||
if (($secure && $port === 443) || (! $secure && $port === 80)) { | ||
return $domain; | ||
} | ||
|
||
return $domain.':'.$port; | ||
} | ||
|
||
/** | ||
* Add a query string to the URI. | ||
* | ||
* @param string $uri | ||
* @param array $parameters | ||
* @return mixed|string | ||
*/ | ||
protected function addQueryString($uri, array $parameters) | ||
{ | ||
// If the URI has a fragment we will move it to the end of this URI since it will | ||
// need to come after any query string that may be added to the URL else it is | ||
// not going to be available. We will remove it then append it back on here. | ||
if (! is_null($fragment = parse_url($uri, PHP_URL_FRAGMENT))) { | ||
$uri = preg_replace('/#.*/', '', $uri); | ||
} | ||
|
||
$uri .= $this->getRouteQueryString($parameters); | ||
|
||
return is_null($fragment) ? $uri : $uri."#{$fragment}"; | ||
} | ||
|
||
/** | ||
* Get the query string for a given route. | ||
* | ||
* @param array $parameters | ||
* @return string | ||
*/ | ||
protected function getRouteQueryString(array $parameters) | ||
{ | ||
// First we will get all of the string parameters that are remaining after we | ||
// have replaced the route wildcards. We'll then build a query string from | ||
// these string parameters then use it as a starting point for the rest. | ||
if (count($parameters) == 0) { | ||
return ''; | ||
} | ||
|
||
$query = http_build_query( | ||
$keyed = $this->getStringParameters($parameters) | ||
); | ||
|
||
// Lastly, if there are still parameters remaining, we will fetch the numeric | ||
// parameters that are in the array and add them to the query string or we | ||
// will make the initial query string if it wasn't started with strings. | ||
if (count($keyed) < count($parameters)) { | ||
$query .= '&'.implode( | ||
'&', $this->getNumericParameters($parameters) | ||
); | ||
} | ||
|
||
return '?'.trim($query, '&'); | ||
} | ||
|
||
/** | ||
* Get the string parameters from a given list. | ||
* | ||
* @param array $parameters | ||
* @return array | ||
*/ | ||
protected function getStringParameters(array $parameters) | ||
{ | ||
return array_filter($parameters, 'is_string', ARRAY_FILTER_USE_KEY); | ||
} | ||
|
||
/** | ||
* Get the numeric parameters from a given list. | ||
* | ||
* @param array $parameters | ||
* @return array | ||
*/ | ||
protected function getNumericParameters(array $parameters) | ||
{ | ||
return array_filter($parameters, 'is_numeric', ARRAY_FILTER_USE_KEY); | ||
} | ||
|
||
/** | ||
* Replace the parameters on the root path. | ||
* | ||
* @param \Illuminate\Routing\Route $route | ||
* @param string $domain | ||
* @param array $parameters | ||
* @return string | ||
*/ | ||
protected function replaceRoot($route, $domain, &$parameters) | ||
{ | ||
return $this->replaceRouteParameters( | ||
$this->formatRouteRoot($route, $domain), $parameters | ||
); | ||
} | ||
|
||
/** | ||
* Get the root of the route URL. | ||
* | ||
* @param \Illuminate\Routing\Route $route | ||
* @param string $domain | ||
* @return string | ||
*/ | ||
protected function formatRouteRoot($route, $domain) | ||
{ | ||
return $this->url->formatRoot($this->getRouteScheme($route), $domain); | ||
} | ||
|
||
/** | ||
* Replace all of the wildcard parameters for a route path. | ||
* | ||
* @param string $path | ||
* @param array $parameters | ||
* @return string | ||
*/ | ||
protected function replaceRouteParameters($path, array &$parameters) | ||
{ | ||
$path = $this->replaceNamedParameters($path, $parameters); | ||
|
||
$path = preg_replace_callback('/\{.*?\}/', function ($match) use (&$parameters) { | ||
return (empty($parameters) && ! Str::endsWith($match[0], '?}')) | ||
? $match[0] | ||
: array_shift($parameters); | ||
}, $path); | ||
|
||
return trim(preg_replace('/\{.*?\?\}/', '', $path), '/'); | ||
} | ||
|
||
/** | ||
* Replace all of the named parameters in the path. | ||
* | ||
* @param string $path | ||
* @param array $parameters | ||
* @return string | ||
*/ | ||
protected function replaceNamedParameters($path, &$parameters) | ||
{ | ||
return preg_replace_callback('/\{(.*?)\??\}/', function ($m) use (&$parameters) { | ||
if (isset($parameters[$m[1]])) { | ||
return Arr::pull($parameters, $m[1]); | ||
} elseif (isset($this->defaultParameters[$m[1]])) { | ||
return $this->defaultParameters[$m[1]]; | ||
} else { | ||
return $m[0]; | ||
} | ||
}, $path); | ||
} | ||
|
||
/** | ||
* Set the default named parameters used by the URL generator. | ||
* | ||
* @param array $defaults | ||
* @return void | ||
*/ | ||
public function defaults(array $defaults) | ||
{ | ||
$this->defaultParameters = array_merge( | ||
$this->defaultParameters, $defaults | ||
); | ||
} | ||
} |
Oops, something went wrong.