/modules/Symfony/Component/Routing/Route.php

https://gitlab.com/x33n/ampache · PHP · 646 lines · 256 code · 73 blank · 317 comment · 14 complexity · 747d3713f1d06b281ce2dd9ec1a3fb98 MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Routing;
  11. /**
  12. * A Route describes a route and its parameters.
  13. *
  14. * @author Fabien Potencier <fabien@symfony.com>
  15. * @author Tobias Schultze <http://tobion.de>
  16. *
  17. * @api
  18. */
  19. class Route implements \Serializable
  20. {
  21. /**
  22. * @var string
  23. */
  24. private $path = '/';
  25. /**
  26. * @var string
  27. */
  28. private $host = '';
  29. /**
  30. * @var array
  31. */
  32. private $schemes = array();
  33. /**
  34. * @var array
  35. */
  36. private $methods = array();
  37. /**
  38. * @var array
  39. */
  40. private $defaults = array();
  41. /**
  42. * @var array
  43. */
  44. private $requirements = array();
  45. /**
  46. * @var array
  47. */
  48. private $options = array();
  49. /**
  50. * @var null|CompiledRoute
  51. */
  52. private $compiled;
  53. private $condition;
  54. /**
  55. * Constructor.
  56. *
  57. * Available options:
  58. *
  59. * * compiler_class: A class name able to compile this route instance (RouteCompiler by default)
  60. *
  61. * @param string $path The path pattern to match
  62. * @param array $defaults An array of default parameter values
  63. * @param array $requirements An array of requirements for parameters (regexes)
  64. * @param array $options An array of options
  65. * @param string $host The host pattern to match
  66. * @param string|array $schemes A required URI scheme or an array of restricted schemes
  67. * @param string|array $methods A required HTTP method or an array of restricted methods
  68. * @param string $condition A condition that should evaluate to true for the route to match
  69. *
  70. * @api
  71. */
  72. public function __construct($path, array $defaults = array(), array $requirements = array(), array $options = array(), $host = '', $schemes = array(), $methods = array(), $condition = null)
  73. {
  74. $this->setPath($path);
  75. $this->setDefaults($defaults);
  76. $this->setRequirements($requirements);
  77. $this->setOptions($options);
  78. $this->setHost($host);
  79. // The conditions make sure that an initial empty $schemes/$methods does not override the corresponding requirement.
  80. // They can be removed when the BC layer is removed.
  81. if ($schemes) {
  82. $this->setSchemes($schemes);
  83. }
  84. if ($methods) {
  85. $this->setMethods($methods);
  86. }
  87. $this->setCondition($condition);
  88. }
  89. public function serialize()
  90. {
  91. return serialize(array(
  92. 'path' => $this->path,
  93. 'host' => $this->host,
  94. 'defaults' => $this->defaults,
  95. 'requirements' => $this->requirements,
  96. 'options' => $this->options,
  97. 'schemes' => $this->schemes,
  98. 'methods' => $this->methods,
  99. 'condition' => $this->condition,
  100. ));
  101. }
  102. public function unserialize($data)
  103. {
  104. $data = unserialize($data);
  105. $this->path = $data['path'];
  106. $this->host = $data['host'];
  107. $this->defaults = $data['defaults'];
  108. $this->requirements = $data['requirements'];
  109. $this->options = $data['options'];
  110. $this->schemes = $data['schemes'];
  111. $this->methods = $data['methods'];
  112. $this->condition = $data['condition'];
  113. }
  114. /**
  115. * Returns the pattern for the path.
  116. *
  117. * @return string The pattern
  118. *
  119. * @deprecated Deprecated in 2.2, to be removed in 3.0. Use getPath instead.
  120. */
  121. public function getPattern()
  122. {
  123. return $this->path;
  124. }
  125. /**
  126. * Sets the pattern for the path.
  127. *
  128. * This method implements a fluent interface.
  129. *
  130. * @param string $pattern The path pattern
  131. *
  132. * @return Route The current Route instance
  133. *
  134. * @deprecated Deprecated in 2.2, to be removed in 3.0. Use setPath instead.
  135. */
  136. public function setPattern($pattern)
  137. {
  138. return $this->setPath($pattern);
  139. }
  140. /**
  141. * Returns the pattern for the path.
  142. *
  143. * @return string The path pattern
  144. */
  145. public function getPath()
  146. {
  147. return $this->path;
  148. }
  149. /**
  150. * Sets the pattern for the path.
  151. *
  152. * This method implements a fluent interface.
  153. *
  154. * @param string $pattern The path pattern
  155. *
  156. * @return Route The current Route instance
  157. */
  158. public function setPath($pattern)
  159. {
  160. // A pattern must start with a slash and must not have multiple slashes at the beginning because the
  161. // generated path for this route would be confused with a network path, e.g. '//domain.com/path'.
  162. $this->path = '/'.ltrim(trim($pattern), '/');
  163. $this->compiled = null;
  164. return $this;
  165. }
  166. /**
  167. * Returns the pattern for the host.
  168. *
  169. * @return string The host pattern
  170. */
  171. public function getHost()
  172. {
  173. return $this->host;
  174. }
  175. /**
  176. * Sets the pattern for the host.
  177. *
  178. * This method implements a fluent interface.
  179. *
  180. * @param string $pattern The host pattern
  181. *
  182. * @return Route The current Route instance
  183. */
  184. public function setHost($pattern)
  185. {
  186. $this->host = (string) $pattern;
  187. $this->compiled = null;
  188. return $this;
  189. }
  190. /**
  191. * Returns the lowercased schemes this route is restricted to.
  192. * So an empty array means that any scheme is allowed.
  193. *
  194. * @return array The schemes
  195. */
  196. public function getSchemes()
  197. {
  198. return $this->schemes;
  199. }
  200. /**
  201. * Sets the schemes (e.g. 'https') this route is restricted to.
  202. * So an empty array means that any scheme is allowed.
  203. *
  204. * This method implements a fluent interface.
  205. *
  206. * @param string|array $schemes The scheme or an array of schemes
  207. *
  208. * @return Route The current Route instance
  209. */
  210. public function setSchemes($schemes)
  211. {
  212. $this->schemes = array_map('strtolower', (array) $schemes);
  213. // this is to keep BC and will be removed in a future version
  214. if ($this->schemes) {
  215. $this->requirements['_scheme'] = implode('|', $this->schemes);
  216. } else {
  217. unset($this->requirements['_scheme']);
  218. }
  219. $this->compiled = null;
  220. return $this;
  221. }
  222. /**
  223. * Checks if a scheme requirement has been set.
  224. *
  225. * @param string $scheme
  226. *
  227. * @return Boolean true if the scheme requirement exists, otherwise false
  228. */
  229. public function hasScheme($scheme)
  230. {
  231. $scheme = strtolower($scheme);
  232. foreach ($this->schemes as $requiredScheme) {
  233. if ($scheme === $requiredScheme) {
  234. return true;
  235. }
  236. }
  237. return false;
  238. }
  239. /**
  240. * Returns the uppercased HTTP methods this route is restricted to.
  241. * So an empty array means that any method is allowed.
  242. *
  243. * @return array The schemes
  244. */
  245. public function getMethods()
  246. {
  247. return $this->methods;
  248. }
  249. /**
  250. * Sets the HTTP methods (e.g. 'POST') this route is restricted to.
  251. * So an empty array means that any method is allowed.
  252. *
  253. * This method implements a fluent interface.
  254. *
  255. * @param string|array $methods The method or an array of methods
  256. *
  257. * @return Route The current Route instance
  258. */
  259. public function setMethods($methods)
  260. {
  261. $this->methods = array_map('strtoupper', (array) $methods);
  262. // this is to keep BC and will be removed in a future version
  263. if ($this->methods) {
  264. $this->requirements['_method'] = implode('|', $this->methods);
  265. } else {
  266. unset($this->requirements['_method']);
  267. }
  268. $this->compiled = null;
  269. return $this;
  270. }
  271. /**
  272. * Returns the options.
  273. *
  274. * @return array The options
  275. */
  276. public function getOptions()
  277. {
  278. return $this->options;
  279. }
  280. /**
  281. * Sets the options.
  282. *
  283. * This method implements a fluent interface.
  284. *
  285. * @param array $options The options
  286. *
  287. * @return Route The current Route instance
  288. */
  289. public function setOptions(array $options)
  290. {
  291. $this->options = array(
  292. 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler',
  293. );
  294. return $this->addOptions($options);
  295. }
  296. /**
  297. * Adds options.
  298. *
  299. * This method implements a fluent interface.
  300. *
  301. * @param array $options The options
  302. *
  303. * @return Route The current Route instance
  304. */
  305. public function addOptions(array $options)
  306. {
  307. foreach ($options as $name => $option) {
  308. $this->options[$name] = $option;
  309. }
  310. $this->compiled = null;
  311. return $this;
  312. }
  313. /**
  314. * Sets an option value.
  315. *
  316. * This method implements a fluent interface.
  317. *
  318. * @param string $name An option name
  319. * @param mixed $value The option value
  320. *
  321. * @return Route The current Route instance
  322. *
  323. * @api
  324. */
  325. public function setOption($name, $value)
  326. {
  327. $this->options[$name] = $value;
  328. $this->compiled = null;
  329. return $this;
  330. }
  331. /**
  332. * Get an option value.
  333. *
  334. * @param string $name An option name
  335. *
  336. * @return mixed The option value or null when not given
  337. */
  338. public function getOption($name)
  339. {
  340. return isset($this->options[$name]) ? $this->options[$name] : null;
  341. }
  342. /**
  343. * Checks if an option has been set
  344. *
  345. * @param string $name An option name
  346. *
  347. * @return Boolean true if the option is set, false otherwise
  348. */
  349. public function hasOption($name)
  350. {
  351. return array_key_exists($name, $this->options);
  352. }
  353. /**
  354. * Returns the defaults.
  355. *
  356. * @return array The defaults
  357. */
  358. public function getDefaults()
  359. {
  360. return $this->defaults;
  361. }
  362. /**
  363. * Sets the defaults.
  364. *
  365. * This method implements a fluent interface.
  366. *
  367. * @param array $defaults The defaults
  368. *
  369. * @return Route The current Route instance
  370. */
  371. public function setDefaults(array $defaults)
  372. {
  373. $this->defaults = array();
  374. return $this->addDefaults($defaults);
  375. }
  376. /**
  377. * Adds defaults.
  378. *
  379. * This method implements a fluent interface.
  380. *
  381. * @param array $defaults The defaults
  382. *
  383. * @return Route The current Route instance
  384. */
  385. public function addDefaults(array $defaults)
  386. {
  387. foreach ($defaults as $name => $default) {
  388. $this->defaults[$name] = $default;
  389. }
  390. $this->compiled = null;
  391. return $this;
  392. }
  393. /**
  394. * Gets a default value.
  395. *
  396. * @param string $name A variable name
  397. *
  398. * @return mixed The default value or null when not given
  399. */
  400. public function getDefault($name)
  401. {
  402. return isset($this->defaults[$name]) ? $this->defaults[$name] : null;
  403. }
  404. /**
  405. * Checks if a default value is set for the given variable.
  406. *
  407. * @param string $name A variable name
  408. *
  409. * @return Boolean true if the default value is set, false otherwise
  410. */
  411. public function hasDefault($name)
  412. {
  413. return array_key_exists($name, $this->defaults);
  414. }
  415. /**
  416. * Sets a default value.
  417. *
  418. * @param string $name A variable name
  419. * @param mixed $default The default value
  420. *
  421. * @return Route The current Route instance
  422. *
  423. * @api
  424. */
  425. public function setDefault($name, $default)
  426. {
  427. $this->defaults[$name] = $default;
  428. $this->compiled = null;
  429. return $this;
  430. }
  431. /**
  432. * Returns the requirements.
  433. *
  434. * @return array The requirements
  435. */
  436. public function getRequirements()
  437. {
  438. return $this->requirements;
  439. }
  440. /**
  441. * Sets the requirements.
  442. *
  443. * This method implements a fluent interface.
  444. *
  445. * @param array $requirements The requirements
  446. *
  447. * @return Route The current Route instance
  448. */
  449. public function setRequirements(array $requirements)
  450. {
  451. $this->requirements = array();
  452. return $this->addRequirements($requirements);
  453. }
  454. /**
  455. * Adds requirements.
  456. *
  457. * This method implements a fluent interface.
  458. *
  459. * @param array $requirements The requirements
  460. *
  461. * @return Route The current Route instance
  462. */
  463. public function addRequirements(array $requirements)
  464. {
  465. foreach ($requirements as $key => $regex) {
  466. $this->requirements[$key] = $this->sanitizeRequirement($key, $regex);
  467. }
  468. $this->compiled = null;
  469. return $this;
  470. }
  471. /**
  472. * Returns the requirement for the given key.
  473. *
  474. * @param string $key The key
  475. *
  476. * @return string|null The regex or null when not given
  477. */
  478. public function getRequirement($key)
  479. {
  480. return isset($this->requirements[$key]) ? $this->requirements[$key] : null;
  481. }
  482. /**
  483. * Checks if a requirement is set for the given key.
  484. *
  485. * @param string $key A variable name
  486. *
  487. * @return Boolean true if a requirement is specified, false otherwise
  488. */
  489. public function hasRequirement($key)
  490. {
  491. return array_key_exists($key, $this->requirements);
  492. }
  493. /**
  494. * Sets a requirement for the given key.
  495. *
  496. * @param string $key The key
  497. * @param string $regex The regex
  498. *
  499. * @return Route The current Route instance
  500. *
  501. * @api
  502. */
  503. public function setRequirement($key, $regex)
  504. {
  505. $this->requirements[$key] = $this->sanitizeRequirement($key, $regex);
  506. $this->compiled = null;
  507. return $this;
  508. }
  509. /**
  510. * Returns the condition.
  511. *
  512. * @return string The condition
  513. */
  514. public function getCondition()
  515. {
  516. return $this->condition;
  517. }
  518. /**
  519. * Sets the condition.
  520. *
  521. * This method implements a fluent interface.
  522. *
  523. * @param string $condition The condition
  524. *
  525. * @return Route The current Route instance
  526. */
  527. public function setCondition($condition)
  528. {
  529. $this->condition = (string) $condition;
  530. $this->compiled = null;
  531. return $this;
  532. }
  533. /**
  534. * Compiles the route.
  535. *
  536. * @return CompiledRoute A CompiledRoute instance
  537. *
  538. * @throws \LogicException If the Route cannot be compiled because the
  539. * path or host pattern is invalid
  540. *
  541. * @see RouteCompiler which is responsible for the compilation process
  542. */
  543. public function compile()
  544. {
  545. if (null !== $this->compiled) {
  546. return $this->compiled;
  547. }
  548. $class = $this->getOption('compiler_class');
  549. return $this->compiled = $class::compile($this);
  550. }
  551. private function sanitizeRequirement($key, $regex)
  552. {
  553. if (!is_string($regex)) {
  554. throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" must be a string.', $key));
  555. }
  556. if ('' !== $regex && '^' === $regex[0]) {
  557. $regex = (string) substr($regex, 1); // returns false for a single character
  558. }
  559. if ('$' === substr($regex, -1)) {
  560. $regex = substr($regex, 0, -1);
  561. }
  562. if ('' === $regex) {
  563. throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" cannot be empty.', $key));
  564. }
  565. // this is to keep BC and will be removed in a future version
  566. if ('_scheme' === $key) {
  567. $this->setSchemes(explode('|', $regex));
  568. } elseif ('_method' === $key) {
  569. $this->setMethods(explode('|', $regex));
  570. }
  571. return $regex;
  572. }
  573. }