PageRenderTime 188ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

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

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