PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/symfony/symfony/src/Symfony/Component/Routing/RouteCollection.php

https://gitlab.com/krlosnando/cenfo-crm
PHP | 344 lines | 165 code | 40 blank | 139 comment | 25 complexity | 2be1e13ffa577e237afa6a72e3209f57 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, LGPL-3.0, BSD-2-Clause
  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. use Symfony\Component\Config\Resource\ResourceInterface;
  12. /**
  13. * A RouteCollection represents a set of Route instances as a tree structure.
  14. *
  15. * When adding a route, it overrides existing routes with the
  16. * same name defined in the instance or its children and parents.
  17. *
  18. * @author Fabien Potencier <fabien@symfony.com>
  19. * @author Tobias Schultze <http://tobion.de>
  20. *
  21. * @api
  22. */
  23. class RouteCollection implements \IteratorAggregate, \Countable
  24. {
  25. private $routes;
  26. private $resources;
  27. private $prefix;
  28. private $parent;
  29. /**
  30. * Constructor.
  31. *
  32. * @api
  33. */
  34. public function __construct()
  35. {
  36. $this->routes = array();
  37. $this->resources = array();
  38. $this->prefix = '';
  39. }
  40. public function __clone()
  41. {
  42. foreach ($this->routes as $name => $route) {
  43. $this->routes[$name] = clone $route;
  44. if ($route instanceof RouteCollection) {
  45. $this->routes[$name]->setParent($this);
  46. }
  47. }
  48. }
  49. /**
  50. * Gets the parent RouteCollection.
  51. *
  52. * @return RouteCollection|null The parent RouteCollection or null when it's the root
  53. */
  54. public function getParent()
  55. {
  56. return $this->parent;
  57. }
  58. /**
  59. * Gets the root RouteCollection of the tree.
  60. *
  61. * @return RouteCollection The root RouteCollection
  62. */
  63. public function getRoot()
  64. {
  65. $parent = $this;
  66. while ($parent->getParent()) {
  67. $parent = $parent->getParent();
  68. }
  69. return $parent;
  70. }
  71. /**
  72. * Gets the current RouteCollection as an Iterator that includes all routes and child route collections.
  73. *
  74. * @return \ArrayIterator An \ArrayIterator interface
  75. */
  76. public function getIterator()
  77. {
  78. return new \ArrayIterator($this->routes);
  79. }
  80. /**
  81. * Gets the number of Routes in this collection.
  82. *
  83. * @return int The number of routes in this collection, including nested collections
  84. */
  85. public function count()
  86. {
  87. $count = 0;
  88. foreach ($this->routes as $route) {
  89. $count += $route instanceof RouteCollection ? count($route) : 1;
  90. }
  91. return $count;
  92. }
  93. /**
  94. * Adds a route.
  95. *
  96. * @param string $name The route name
  97. * @param Route $route A Route instance
  98. *
  99. * @throws \InvalidArgumentException When route name contains non valid characters
  100. *
  101. * @api
  102. */
  103. public function add($name, Route $route)
  104. {
  105. if (!preg_match('/^[a-z0-9A-Z_.]+$/', $name)) {
  106. throw new \InvalidArgumentException(sprintf('The provided route name "%s" contains non valid characters. A route name must only contain digits (0-9), letters (a-z and A-Z), underscores (_) and dots (.).', $name));
  107. }
  108. $this->remove($name);
  109. $this->routes[$name] = $route;
  110. }
  111. /**
  112. * Returns all routes in this collection and its children.
  113. *
  114. * @return array An array of routes
  115. */
  116. public function all()
  117. {
  118. $routes = array();
  119. foreach ($this->routes as $name => $route) {
  120. if ($route instanceof RouteCollection) {
  121. $routes = array_merge($routes, $route->all());
  122. } else {
  123. $routes[$name] = $route;
  124. }
  125. }
  126. return $routes;
  127. }
  128. /**
  129. * Gets a route by name defined in this collection or its children.
  130. *
  131. * @param string $name The route name
  132. *
  133. * @return Route|null A Route instance or null when not found
  134. */
  135. public function get($name)
  136. {
  137. if (isset($this->routes[$name])) {
  138. return $this->routes[$name] instanceof RouteCollection ? null : $this->routes[$name];
  139. }
  140. foreach ($this->routes as $routes) {
  141. if ($routes instanceof RouteCollection && null !== $route = $routes->get($name)) {
  142. return $route;
  143. }
  144. }
  145. return null;
  146. }
  147. /**
  148. * Removes a route or an array of routes by name from all connected
  149. * collections (this instance and all parents and children).
  150. *
  151. * @param string|array $name The route name or an array of route names
  152. */
  153. public function remove($name)
  154. {
  155. $root = $this->getRoot();
  156. foreach ((array) $name as $n) {
  157. $root->removeRecursively($n);
  158. }
  159. }
  160. /**
  161. * Adds a route collection to the current set of routes (at the end of the current set).
  162. *
  163. * @param RouteCollection $collection A RouteCollection instance
  164. * @param string $prefix An optional prefix to add before each pattern of the route collection
  165. * @param array $defaults An array of default values
  166. * @param array $requirements An array of requirements
  167. * @param array $options An array of options
  168. *
  169. * @throws \InvalidArgumentException When the RouteCollection already exists in the tree
  170. *
  171. * @api
  172. */
  173. public function addCollection(RouteCollection $collection, $prefix = '', $defaults = array(), $requirements = array(), $options = array())
  174. {
  175. // prevent infinite loops by recursive referencing
  176. $root = $this->getRoot();
  177. if ($root === $collection || $root->hasCollection($collection)) {
  178. throw new \InvalidArgumentException('The RouteCollection already exists in the tree.');
  179. }
  180. // remove all routes with the same names in all existing collections
  181. $this->remove(array_keys($collection->all()));
  182. $collection->setParent($this);
  183. // the sub-collection must have the prefix of the parent (current instance) prepended because it does not
  184. // necessarily already have it applied (depending on the order RouteCollections are added to each other)
  185. $collection->addPrefix($this->getPrefix() . $prefix, $defaults, $requirements, $options);
  186. $this->routes[] = $collection;
  187. }
  188. /**
  189. * Adds a prefix to all routes in the current set.
  190. *
  191. * @param string $prefix An optional prefix to add before each pattern of the route collection
  192. * @param array $defaults An array of default values
  193. * @param array $requirements An array of requirements
  194. * @param array $options An array of options
  195. *
  196. * @api
  197. */
  198. public function addPrefix($prefix, $defaults = array(), $requirements = array(), $options = array())
  199. {
  200. $prefix = trim(trim($prefix), '/');
  201. if ('' === $prefix && empty($defaults) && empty($requirements) && empty($options)) {
  202. return;
  203. }
  204. // a prefix must start with a single slash and must not end with a slash
  205. if ('' !== $prefix) {
  206. $this->prefix = '/' . $prefix . $this->prefix;
  207. }
  208. foreach ($this->routes as $route) {
  209. if ($route instanceof RouteCollection) {
  210. // we add the slashes so the prefix is not lost by trimming in the sub-collection
  211. $route->addPrefix('/' . $prefix . '/', $defaults, $requirements, $options);
  212. } else {
  213. if ('' !== $prefix) {
  214. $route->setPattern('/' . $prefix . $route->getPattern());
  215. }
  216. $route->addDefaults($defaults);
  217. $route->addRequirements($requirements);
  218. $route->addOptions($options);
  219. }
  220. }
  221. }
  222. /**
  223. * Returns the prefix that may contain placeholders.
  224. *
  225. * @return string The prefix
  226. */
  227. public function getPrefix()
  228. {
  229. return $this->prefix;
  230. }
  231. /**
  232. * Returns an array of resources loaded to build this collection.
  233. *
  234. * @return ResourceInterface[] An array of resources
  235. */
  236. public function getResources()
  237. {
  238. $resources = $this->resources;
  239. foreach ($this->routes as $routes) {
  240. if ($routes instanceof RouteCollection) {
  241. $resources = array_merge($resources, $routes->getResources());
  242. }
  243. }
  244. return array_unique($resources);
  245. }
  246. /**
  247. * Adds a resource for this collection.
  248. *
  249. * @param ResourceInterface $resource A resource instance
  250. */
  251. public function addResource(ResourceInterface $resource)
  252. {
  253. $this->resources[] = $resource;
  254. }
  255. /**
  256. * Sets the parent RouteCollection. It's only used internally from one RouteCollection
  257. * to another. It makes no sense to be available as part of the public API.
  258. *
  259. * @param RouteCollection $parent The parent RouteCollection
  260. */
  261. private function setParent(RouteCollection $parent)
  262. {
  263. $this->parent = $parent;
  264. }
  265. /**
  266. * Removes a route by name from this collection and its children recursively.
  267. *
  268. * @param string $name The route name
  269. *
  270. * @return Boolean true when found
  271. */
  272. private function removeRecursively($name)
  273. {
  274. // It is ensured by the adders (->add and ->addCollection) that there can
  275. // only be one route per name in all connected collections. So we can stop
  276. // iterating recursively on the first hit.
  277. if (isset($this->routes[$name])) {
  278. unset($this->routes[$name]);
  279. return true;
  280. }
  281. foreach ($this->routes as $routes) {
  282. if ($routes instanceof RouteCollection && $routes->removeRecursively($name)) {
  283. return true;
  284. }
  285. }
  286. return false;
  287. }
  288. /**
  289. * Checks whether the given RouteCollection is already set in any child of the current instance.
  290. *
  291. * @param RouteCollection $collection A RouteCollection instance
  292. *
  293. * @return Boolean
  294. */
  295. private function hasCollection(RouteCollection $collection)
  296. {
  297. foreach ($this->routes as $routes) {
  298. if ($routes === $collection || $routes instanceof RouteCollection && $routes->hasCollection($collection)) {
  299. return true;
  300. }
  301. }
  302. return false;
  303. }
  304. }