Route.php 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. <?php
  2. /**
  3. * @package Grav\Framework\Route
  4. *
  5. * @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. namespace Grav\Framework\Route;
  9. use Grav\Framework\Uri\UriFactory;
  10. /**
  11. * Implements Grav Route.
  12. *
  13. * @package Grav\Framework\Route
  14. */
  15. class Route
  16. {
  17. /** @var string */
  18. private $root = '';
  19. /** @var string */
  20. private $language = '';
  21. /** @var string */
  22. private $route = '';
  23. /** @var array */
  24. private $gravParams = [];
  25. /** @var array */
  26. private $queryParams = [];
  27. /**
  28. * You can use `RouteFactory` functions to create new `Route` objects.
  29. *
  30. * @param array $parts
  31. * @throws \InvalidArgumentException
  32. */
  33. public function __construct(array $parts = [])
  34. {
  35. $this->initParts($parts);
  36. }
  37. /**
  38. * @return array
  39. */
  40. public function getParts()
  41. {
  42. return [
  43. 'path' => $this->getUriPath(),
  44. 'query' => $this->getUriQuery(),
  45. 'grav' => [
  46. 'root' => $this->root,
  47. 'language' => $this->language,
  48. 'route' => $this->route,
  49. 'grav_params' => $this->gravParams,
  50. 'query_params' => $this->queryParams,
  51. ],
  52. ];
  53. }
  54. /**
  55. * @return string
  56. */
  57. public function getRootPrefix()
  58. {
  59. return $this->root;
  60. }
  61. /**
  62. * @return string
  63. */
  64. public function getLanguagePrefix()
  65. {
  66. return $this->language !== '' ? '/' . $this->language : '';
  67. }
  68. /**
  69. * @param int $offset
  70. * @param int|null $length
  71. * @return string
  72. */
  73. public function getRoute($offset = 0, $length = null)
  74. {
  75. if ($offset !== 0 || $length !== null) {
  76. return ($offset === 0 ? '/' : '') . implode('/', $this->getRouteParts($offset, $length));
  77. }
  78. return '/' . $this->route;
  79. }
  80. /**
  81. * @param int $offset
  82. * @param int|null $length
  83. * @return array
  84. */
  85. public function getRouteParts($offset = 0, $length = null)
  86. {
  87. $parts = explode('/', $this->route);
  88. if ($offset !== 0 || $length !== null) {
  89. $parts = array_slice($parts, $offset, $length);
  90. }
  91. return $parts;
  92. }
  93. /**
  94. * Return array of both query and Grav parameters.
  95. *
  96. * If a parameter exists in both, prefer Grav parameter.
  97. *
  98. * @return array
  99. */
  100. public function getParams()
  101. {
  102. return $this->gravParams + $this->queryParams;
  103. }
  104. /**
  105. * @return array
  106. */
  107. public function getGravParams()
  108. {
  109. return $this->gravParams;
  110. }
  111. /**
  112. * @return array
  113. */
  114. public function getQueryParams()
  115. {
  116. return $this->queryParams;
  117. }
  118. /**
  119. * Return value of the parameter, looking into both Grav parameters and query parameters.
  120. *
  121. * If the parameter exists in both, return Grav parameter.
  122. *
  123. * @param string $param
  124. * @return string|null
  125. */
  126. public function getParam($param)
  127. {
  128. $value = $this->getGravParam($param);
  129. if ($value === null) {
  130. $value = $this->getQueryParam($param);
  131. }
  132. return $value;
  133. }
  134. /**
  135. * @param string $param
  136. * @return string|null
  137. */
  138. public function getGravParam($param)
  139. {
  140. return isset($this->gravParams[$param]) ? $this->gravParams[$param] : null;
  141. }
  142. /**
  143. * @param string $param
  144. * @return string|null
  145. */
  146. public function getQueryParam($param)
  147. {
  148. return isset($this->queryParams[$param]) ? $this->queryParams[$param] : null;
  149. }
  150. /**
  151. * @param string $param
  152. * @param mixed $value
  153. * @return Route
  154. */
  155. public function withGravParam($param, $value)
  156. {
  157. return $this->withParam('gravParams', $param, null !== $value ? (string)$value : null);
  158. }
  159. /**
  160. * @param string $param
  161. * @param mixed $value
  162. * @return Route
  163. */
  164. public function withQueryParam($param, $value)
  165. {
  166. return $this->withParam('queryParams', $param, $value);
  167. }
  168. /**
  169. * @return \Grav\Framework\Uri\Uri
  170. */
  171. public function getUri()
  172. {
  173. return UriFactory::createFromParts($this->getParts());
  174. }
  175. /**
  176. * @return string
  177. */
  178. public function __toString()
  179. {
  180. $url = $this->getUriPath();
  181. if ($this->queryParams) {
  182. $url .= '?' . $this->getUriQuery();
  183. }
  184. return $url;
  185. }
  186. /**
  187. * @param string $type
  188. * @param string $param
  189. * @param mixed $value
  190. * @return static
  191. */
  192. protected function withParam($type, $param, $value)
  193. {
  194. $oldValue = isset($this->{$type}[$param]) ? $this->{$type}[$param] : null;
  195. if ($oldValue === $value) {
  196. return $this;
  197. }
  198. $new = clone $this;
  199. if ($value === null) {
  200. unset($new->{$type}[$param]);
  201. } else {
  202. $new->{$type}[$param] = $value;
  203. }
  204. return $new;
  205. }
  206. /**
  207. * @return string
  208. */
  209. protected function getUriPath()
  210. {
  211. $parts = [$this->root];
  212. if ($this->language !== '') {
  213. $parts[] = $this->language;
  214. }
  215. if ($this->route !== '') {
  216. $parts[] = $this->route;
  217. }
  218. if ($this->gravParams) {
  219. $parts[] = RouteFactory::buildParams($this->gravParams);
  220. }
  221. return implode('/', $parts);
  222. }
  223. /**
  224. * @return string
  225. */
  226. protected function getUriQuery()
  227. {
  228. return UriFactory::buildQuery($this->queryParams);
  229. }
  230. /**
  231. * @param array $parts
  232. */
  233. protected function initParts(array $parts)
  234. {
  235. if (isset($parts['grav'])) {
  236. $gravParts = $parts['grav'];
  237. $this->root = $gravParts['root'];
  238. $this->language = $gravParts['language'];
  239. $this->route = $gravParts['route'];
  240. $this->gravParams = $gravParts['params'];
  241. $this->queryParams = $parts['query_params'];
  242. } else {
  243. $this->root = RouteFactory::getRoot();
  244. $this->language = RouteFactory::getLanguage();
  245. $path = isset($parts['path']) ? $parts['path'] : '/';
  246. if (isset($parts['params'])) {
  247. $this->route = trim(rawurldecode($path), '/');
  248. $this->gravParams = $parts['params'];
  249. } else {
  250. $this->route = trim(RouteFactory::stripParams($path, true), '/');
  251. $this->gravParams = RouteFactory::getParams($path);
  252. }
  253. if (isset($parts['query'])) {
  254. $this->queryParams = UriFactory::parseQuery($parts['query']);
  255. }
  256. }
  257. }
  258. }