PageRenderTime 60ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php

https://gitlab.com/techniconline/kmc
PHP | 698 lines | 295 code | 87 blank | 316 comment | 17 complexity | a0f90419390ea00a2414267a148ed443 MD5 | raw file
  1. <?php namespace Illuminate\Routing;
  2. use Illuminate\Http\Request;
  3. use InvalidArgumentException;
  4. use Illuminate\Contracts\Routing\UrlRoutable;
  5. use Illuminate\Contracts\Routing\UrlGenerator as UrlGeneratorContract;
  6. class UrlGenerator implements UrlGeneratorContract
  7. {
  8. /**
  9. * The route collection.
  10. *
  11. * @var \Illuminate\Routing\RouteCollection
  12. */
  13. protected $routes;
  14. /**
  15. * The request instance.
  16. *
  17. * @var \Illuminate\Http\Request
  18. */
  19. protected $request;
  20. /**
  21. * The forced URL root.
  22. *
  23. * @var string
  24. */
  25. protected $forcedRoot;
  26. /**
  27. * The forced schema for URLs.
  28. *
  29. * @var string
  30. */
  31. protected $forceSchema;
  32. /**
  33. * A cached copy of the URL root for the current request.
  34. *
  35. * @var string|null
  36. */
  37. protected $cachedRoot;
  38. /**
  39. * A cached copy of the URL schema for the current request.
  40. *
  41. * @var string|null
  42. */
  43. protected $cachedSchema;
  44. /**
  45. * The root namespace being applied to controller actions.
  46. *
  47. * @var string
  48. */
  49. protected $rootNamespace;
  50. /**
  51. * The session resolver callable.
  52. *
  53. * @var callable
  54. */
  55. protected $sessionResolver;
  56. /**
  57. * Characters that should not be URL encoded.
  58. *
  59. * @var array
  60. */
  61. protected $dontEncode = array(
  62. '%2F' => '/',
  63. '%40' => '@',
  64. '%3A' => ':',
  65. '%3B' => ';',
  66. '%2C' => ',',
  67. '%3D' => '=',
  68. '%2B' => '+',
  69. '%21' => '!',
  70. '%2A' => '*',
  71. '%7C' => '|',
  72. '%3F' => '?',
  73. '%26' => '&',
  74. '%23' => '#',
  75. '%25' => '%',
  76. );
  77. /**
  78. * Create a new URL Generator instance.
  79. *
  80. * @param \Illuminate\Routing\RouteCollection $routes
  81. * @param \Illuminate\Http\Request $request
  82. * @return void
  83. */
  84. public function __construct(RouteCollection $routes, Request $request)
  85. {
  86. $this->routes = $routes;
  87. $this->setRequest($request);
  88. }
  89. /**
  90. * Get the full URL for the current request.
  91. *
  92. * @return string
  93. */
  94. public function full()
  95. {
  96. return $this->request->fullUrl();
  97. }
  98. /**
  99. * Get the current URL for the request.
  100. *
  101. * @return string
  102. */
  103. public function current()
  104. {
  105. return $this->to($this->request->getPathInfo());
  106. }
  107. /**
  108. * Get the URL for the previous request.
  109. *
  110. * @return string
  111. */
  112. public function previous()
  113. {
  114. $referrer = $this->request->headers->get('referer');
  115. $url = $referrer ? $this->to($referrer) : $this->getPreviousUrlFromSession();
  116. return $url ?: $this->to('/');
  117. }
  118. /**
  119. * Generate a absolute URL to the given path.
  120. *
  121. * @param string $path
  122. * @param mixed $extra
  123. * @param bool|null $secure
  124. * @return string
  125. */
  126. public function to($path, $extra = array(), $secure = null)
  127. {
  128. // First we will check if the URL is already a valid URL. If it is we will not
  129. // try to generate a new one but will simply return the URL as is, which is
  130. // convenient since developers do not always have to check if it's valid.
  131. if ($this->isValidUrl($path)) return $path;
  132. $scheme = $this->getScheme($secure);
  133. $extra = $this->formatParameters($extra);
  134. $tail = implode('/', array_map(
  135. 'rawurlencode', (array)$extra)
  136. );
  137. // Once we have the scheme we will compile the "tail" by collapsing the values
  138. // into a single string delimited by slashes. This just makes it convenient
  139. // for passing the array of parameters to this URL as a list of segments.
  140. $root = $this->getRootUrl($scheme);
  141. return $this->trimUrl($root, $path, $tail);
  142. }
  143. /**
  144. * Generate a secure, absolute URL to the given path.
  145. *
  146. * @param string $path
  147. * @param array $parameters
  148. * @return string
  149. */
  150. public function secure($path, $parameters = array())
  151. {
  152. return $this->to($path, $parameters, true);
  153. }
  154. /**
  155. * Generate a URL to an application asset.
  156. *
  157. * @param string $path
  158. * @param bool|null $secure
  159. * @return string
  160. */
  161. public function asset($path, $secure = null)
  162. {
  163. if ($this->isValidUrl($path)) return $path;
  164. // Once we get the root URL, we will check to see if it contains an index.php
  165. // file in the paths. If it does, we will remove it since it is not needed
  166. // for asset paths, but only for routes to endpoints in the application.
  167. $root = $this->getRootUrl($this->getScheme($secure));
  168. return $this->removeIndex($root) . '/' . trim($path, '/');
  169. }
  170. /**
  171. * Remove the index.php file from a path.
  172. *
  173. * @param string $root
  174. * @return string
  175. */
  176. protected function removeIndex($root)
  177. {
  178. $i = 'index.php';
  179. return str_contains($root, $i) ? str_replace('/' . $i, '', $root) : $root;
  180. }
  181. /**
  182. * Generate a URL to a secure asset.
  183. *
  184. * @param string $path
  185. * @return string
  186. */
  187. public function secureAsset($path)
  188. {
  189. return $this->asset($path, true);
  190. }
  191. /**
  192. * Get the scheme for a raw URL.
  193. *
  194. * @param bool|null $secure
  195. * @return string
  196. */
  197. protected function getScheme($secure)
  198. {
  199. if (is_null($secure)) {
  200. if (is_null($this->cachedSchema)) {
  201. $this->cachedSchema = $this->forceSchema ?: $this->request->getScheme() . '://';
  202. }
  203. return $this->cachedSchema;
  204. }
  205. return $secure ? 'https://' : 'http://';
  206. }
  207. /**
  208. * Force the schema for URLs.
  209. *
  210. * @param string $schema
  211. * @return void
  212. */
  213. public function forceSchema($schema)
  214. {
  215. $this->cachedSchema = null;
  216. $this->forceSchema = $schema . '://';
  217. }
  218. /**
  219. * Get the URL to a named route.
  220. *
  221. * @param string $name
  222. * @param mixed $parameters
  223. * @param bool $absolute
  224. * @return string
  225. *
  226. * @throws \InvalidArgumentException
  227. */
  228. public function route($name, $parameters = array(), $absolute = true)
  229. {
  230. if (!is_null($route = $this->routes->getByName($name))) {
  231. return $this->toRoute($route, $parameters, $absolute);
  232. }
  233. throw new InvalidArgumentException("Route [{$name}] not defined.");
  234. }
  235. /**
  236. * Get the URL for a given route instance.
  237. *
  238. * @param \Illuminate\Routing\Route $route
  239. * @param mixed $parameters
  240. * @param bool $absolute
  241. * @return string
  242. */
  243. protected function toRoute($route, $parameters, $absolute)
  244. {
  245. $parameters = $this->formatParameters($parameters);
  246. $domain = $this->getRouteDomain($route, $parameters);
  247. $uri = strtr(rawurlencode($this->addQueryString($this->trimUrl(
  248. $root = $this->replaceRoot($route, $domain, $parameters),
  249. $this->replaceRouteParameters($route->uri(), $parameters)
  250. ), $parameters)), $this->dontEncode);
  251. return $absolute ? $uri : '/' . ltrim(str_replace($root, '', $uri), '/');
  252. }
  253. /**
  254. * Replace the parameters on the root path.
  255. *
  256. * @param \Illuminate\Routing\Route $route
  257. * @param string $domain
  258. * @param array $parameters
  259. * @return string
  260. */
  261. protected function replaceRoot($route, $domain, &$parameters)
  262. {
  263. return $this->replaceRouteParameters($this->getRouteRoot($route, $domain), $parameters);
  264. }
  265. /**
  266. * Replace all of the wildcard parameters for a route path.
  267. *
  268. * @param string $path
  269. * @param array $parameters
  270. * @return string
  271. */
  272. protected function replaceRouteParameters($path, array &$parameters)
  273. {
  274. if (count($parameters)) {
  275. $path = preg_replace_sub(
  276. '/\{.*?\}/', $parameters, $this->replaceNamedParameters($path, $parameters)
  277. );
  278. }
  279. return trim(preg_replace('/\{.*?\?\}/', '', $path), '/');
  280. }
  281. /**
  282. * Replace all of the named parameters in the path.
  283. *
  284. * @param string $path
  285. * @param array $parameters
  286. * @return string
  287. */
  288. protected function replaceNamedParameters($path, &$parameters)
  289. {
  290. return preg_replace_callback('/\{(.*?)\??\}/', function ($m) use (&$parameters) {
  291. return isset($parameters[$m[1]]) ? array_pull($parameters, $m[1]) : $m[0];
  292. }, $path);
  293. }
  294. /**
  295. * Add a query string to the URI.
  296. *
  297. * @param string $uri
  298. * @param array $parameters
  299. * @return mixed|string
  300. */
  301. protected function addQueryString($uri, array $parameters)
  302. {
  303. // If the URI has a fragment, we will move it to the end of the URI since it will
  304. // need to come after any query string that may be added to the URL else it is
  305. // not going to be available. We will remove it then append it back on here.
  306. if (!is_null($fragment = parse_url($uri, PHP_URL_FRAGMENT))) {
  307. $uri = preg_replace('/#.*/', '', $uri);
  308. }
  309. $uri .= $this->getRouteQueryString($parameters);
  310. return is_null($fragment) ? $uri : $uri . "#{$fragment}";
  311. }
  312. /**
  313. * Format the array of URL parameters.
  314. *
  315. * @param mixed|array $parameters
  316. * @return array
  317. */
  318. protected function formatParameters($parameters)
  319. {
  320. return $this->replaceRoutableParameters($parameters);
  321. }
  322. /**
  323. * Replace UrlRoutable parameters with their route parameter.
  324. *
  325. * @param array $parameters
  326. * @return array
  327. */
  328. protected function replaceRoutableParameters($parameters = array())
  329. {
  330. $parameters = is_array($parameters) ? $parameters : array($parameters);
  331. foreach ($parameters as $key => $parameter) {
  332. if ($parameter instanceof UrlRoutable) {
  333. $parameters[$key] = $parameter->getRouteKey();
  334. }
  335. }
  336. return $parameters;
  337. }
  338. /**
  339. * Get the query string for a given route.
  340. *
  341. * @param array $parameters
  342. * @return string
  343. */
  344. protected function getRouteQueryString(array $parameters)
  345. {
  346. // First we will get all of the string parameters that are remaining after we
  347. // have replaced the route wildcards. We'll then build a query string from
  348. // these string parameters then use it as a starting point for the rest.
  349. if (count($parameters) == 0) return '';
  350. $query = http_build_query(
  351. $keyed = $this->getStringParameters($parameters)
  352. );
  353. // Lastly, if there are still parameters remaining, we will fetch the numeric
  354. // parameters that are in the array and add them to the query string or we
  355. // will make the initial query string if it wasn't started with strings.
  356. if (count($keyed) < count($parameters)) {
  357. $query .= '&' . implode(
  358. '&', $this->getNumericParameters($parameters)
  359. );
  360. }
  361. return '?' . trim($query, '&');
  362. }
  363. /**
  364. * Get the string parameters from a given list.
  365. *
  366. * @param array $parameters
  367. * @return array
  368. */
  369. protected function getStringParameters(array $parameters)
  370. {
  371. return array_where($parameters, function ($k, $v) {
  372. return is_string($k);
  373. });
  374. }
  375. /**
  376. * Get the numeric parameters from a given list.
  377. *
  378. * @param array $parameters
  379. * @return array
  380. */
  381. protected function getNumericParameters(array $parameters)
  382. {
  383. return array_where($parameters, function ($k, $v) {
  384. return is_numeric($k);
  385. });
  386. }
  387. /**
  388. * Get the formatted domain for a given route.
  389. *
  390. * @param \Illuminate\Routing\Route $route
  391. * @param array $parameters
  392. * @return string
  393. */
  394. protected function getRouteDomain($route, &$parameters)
  395. {
  396. return $route->domain() ? $this->formatDomain($route, $parameters) : null;
  397. }
  398. /**
  399. * Format the domain and port for the route and request.
  400. *
  401. * @param \Illuminate\Routing\Route $route
  402. * @param array $parameters
  403. * @return string
  404. */
  405. protected function formatDomain($route, &$parameters)
  406. {
  407. return $this->addPortToDomain($this->getDomainAndScheme($route));
  408. }
  409. /**
  410. * Get the domain and scheme for the route.
  411. *
  412. * @param \Illuminate\Routing\Route $route
  413. * @return string
  414. */
  415. protected function getDomainAndScheme($route)
  416. {
  417. return $this->getRouteScheme($route) . $route->domain();
  418. }
  419. /**
  420. * Add the port to the domain if necessary.
  421. *
  422. * @param string $domain
  423. * @return string
  424. */
  425. protected function addPortToDomain($domain)
  426. {
  427. if (in_array($this->request->getPort(), array('80', '443'))) {
  428. return $domain;
  429. }
  430. return $domain . ':' . $this->request->getPort();
  431. }
  432. /**
  433. * Get the root of the route URL.
  434. *
  435. * @param \Illuminate\Routing\Route $route
  436. * @param string $domain
  437. * @return string
  438. */
  439. protected function getRouteRoot($route, $domain)
  440. {
  441. return $this->getRootUrl($this->getRouteScheme($route), $domain);
  442. }
  443. /**
  444. * Get the scheme for the given route.
  445. *
  446. * @param \Illuminate\Routing\Route $route
  447. * @return string
  448. */
  449. protected function getRouteScheme($route)
  450. {
  451. if ($route->httpOnly()) {
  452. return $this->getScheme(false);
  453. } elseif ($route->httpsOnly()) {
  454. return $this->getScheme(true);
  455. }
  456. return $this->getScheme(null);
  457. }
  458. /**
  459. * Get the URL to a controller action.
  460. *
  461. * @param string $action
  462. * @param mixed $parameters
  463. * @param bool $absolute
  464. * @return string
  465. *
  466. * @throws \InvalidArgumentException
  467. */
  468. public function action($action, $parameters = array(), $absolute = true)
  469. {
  470. if ($this->rootNamespace && !(strpos($action, '\\') === 0)) {
  471. $action = $this->rootNamespace . '\\' . $action;
  472. } else {
  473. $action = trim($action, '\\');
  474. }
  475. if (!is_null($route = $this->routes->getByAction($action))) {
  476. return $this->toRoute($route, $parameters, $absolute);
  477. }
  478. throw new InvalidArgumentException("Action {$action} not defined.");
  479. }
  480. /**
  481. * Get the base URL for the request.
  482. *
  483. * @param string $scheme
  484. * @param string $root
  485. * @return string
  486. */
  487. protected function getRootUrl($scheme, $root = null)
  488. {
  489. if (is_null($root)) {
  490. if (is_null($this->cachedRoot)) {
  491. $this->cachedRoot = $this->forcedRoot ?: $this->request->root();
  492. }
  493. $root = $this->cachedRoot;
  494. }
  495. $start = starts_with($root, 'http://') ? 'http://' : 'https://';
  496. return preg_replace('~' . $start . '~', $scheme, $root, 1);
  497. }
  498. /**
  499. * Set the forced root URL.
  500. *
  501. * @param string $root
  502. * @return void
  503. */
  504. public function forceRootUrl($root)
  505. {
  506. $this->forcedRoot = rtrim($root, '/');
  507. $this->cachedRoot = null;
  508. }
  509. /**
  510. * Determine if the given path is a valid URL.
  511. *
  512. * @param string $path
  513. * @return bool
  514. */
  515. public function isValidUrl($path)
  516. {
  517. if (starts_with($path, ['#', '//', 'mailto:', 'tel:', 'http://', 'https://'])) return true;
  518. return filter_var($path, FILTER_VALIDATE_URL) !== false;
  519. }
  520. /**
  521. * Format the given URL segments into a single URL.
  522. *
  523. * @param string $root
  524. * @param string $path
  525. * @param string $tail
  526. * @return string
  527. */
  528. protected function trimUrl($root, $path, $tail = '')
  529. {
  530. return trim($root . '/' . trim($path . '/' . $tail, '/'), '/');
  531. }
  532. /**
  533. * Get the request instance.
  534. *
  535. * @return \Symfony\Component\HttpFoundation\Request
  536. */
  537. public function getRequest()
  538. {
  539. return $this->request;
  540. }
  541. /**
  542. * Set the current request instance.
  543. *
  544. * @param \Illuminate\Http\Request $request
  545. * @return void
  546. */
  547. public function setRequest(Request $request)
  548. {
  549. $this->request = $request;
  550. $this->cachedRoot = null;
  551. $this->cachedSchema = null;
  552. }
  553. /**
  554. * Set the route collection.
  555. *
  556. * @param \Illuminate\Routing\RouteCollection $routes
  557. * @return $this
  558. */
  559. public function setRoutes(RouteCollection $routes)
  560. {
  561. $this->routes = $routes;
  562. return $this;
  563. }
  564. /**
  565. * Get the previous URL from the session if possible.
  566. *
  567. * @return string|null
  568. */
  569. protected function getPreviousUrlFromSession()
  570. {
  571. $session = $this->getSession();
  572. return $session ? $session->previousUrl() : null;
  573. }
  574. /**
  575. * Get the session implementation from the resolver.
  576. *
  577. * @return \Illuminate\Session\Store
  578. */
  579. protected function getSession()
  580. {
  581. return call_user_func($this->sessionResolver ?: function () {
  582. });
  583. }
  584. /**
  585. * Set the session resolver for the generator.
  586. *
  587. * @param callable $sessionResolver
  588. * @return $this
  589. */
  590. public function setSessionResolver(callable $sessionResolver)
  591. {
  592. $this->sessionResolver = $sessionResolver;
  593. return $this;
  594. }
  595. /**
  596. * Set the root controller namespace.
  597. *
  598. * @param string $rootNamespace
  599. * @return $this
  600. */
  601. public function setRootControllerNamespace($rootNamespace)
  602. {
  603. $this->rootNamespace = $rootNamespace;
  604. return $this;
  605. }
  606. }