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

https://github.com/stedekay/symfony · PHP · 255 lines · 126 code · 31 blank · 98 comment · 15 complexity · c047dca02035fb807031e1f43e909754 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. use Symfony\Component\Config\Resource\ResourceInterface;
  12. /**
  13. * A RouteCollection represents a set of Route instances.
  14. *
  15. * When adding a route, it overrides existing routes with the
  16. * same name defined in theinstance or its children and parents.
  17. *
  18. * @author Fabien Potencier <fabien@symfony.com>
  19. *
  20. * @api
  21. */
  22. class RouteCollection implements \IteratorAggregate
  23. {
  24. private $routes;
  25. private $resources;
  26. private $prefix;
  27. private $parent;
  28. /**
  29. * Constructor.
  30. *
  31. * @api
  32. */
  33. public function __construct()
  34. {
  35. $this->routes = array();
  36. $this->resources = array();
  37. $this->prefix = '';
  38. }
  39. /**
  40. * Gets the parent RouteCollection.
  41. *
  42. * @return RouteCollection The parent RouteCollection
  43. */
  44. public function getParent()
  45. {
  46. return $this->parent;
  47. }
  48. /**
  49. * Sets the parent RouteCollection.
  50. *
  51. * @param RouteCollection $parent The parent RouteCollection
  52. */
  53. public function setParent(RouteCollection $parent)
  54. {
  55. $this->parent = $parent;
  56. }
  57. /**
  58. * Gets the current RouteCollection as an Iterator.
  59. *
  60. * @return \ArrayIterator An \ArrayIterator interface
  61. */
  62. public function getIterator()
  63. {
  64. return new \ArrayIterator($this->routes);
  65. }
  66. /**
  67. * Adds a route.
  68. *
  69. * @param string $name The route name
  70. * @param Route $route A Route instance
  71. *
  72. * @throws \InvalidArgumentException When route name contains non valid characters
  73. *
  74. * @api
  75. */
  76. public function add($name, Route $route)
  77. {
  78. if (!preg_match('/^[a-z0-9A-Z_.]+$/', $name)) {
  79. throw new \InvalidArgumentException(sprintf('Name "%s" contains non valid characters for a route name.', $name));
  80. }
  81. $parent = $this;
  82. while ($parent->getParent()) {
  83. $parent = $parent->getParent();
  84. }
  85. if ($parent) {
  86. $parent->remove($name);
  87. }
  88. $this->routes[$name] = $route;
  89. }
  90. /**
  91. * Returns the array of routes.
  92. *
  93. * @return array An array of routes
  94. */
  95. public function all()
  96. {
  97. $routes = array();
  98. foreach ($this->routes as $name => $route) {
  99. if ($route instanceof RouteCollection) {
  100. $routes = array_merge($routes, $route->all());
  101. } else {
  102. $routes[$name] = $route;
  103. }
  104. }
  105. return $routes;
  106. }
  107. /**
  108. * Gets a route by name.
  109. *
  110. * @param string $name The route name
  111. *
  112. * @return Route $route A Route instance
  113. */
  114. public function get($name)
  115. {
  116. // get the latest defined route
  117. foreach (array_reverse($this->routes) as $routes) {
  118. if (!$routes instanceof RouteCollection) {
  119. continue;
  120. }
  121. if (null !== $route = $routes->get($name)) {
  122. return $route;
  123. }
  124. }
  125. if (isset($this->routes[$name])) {
  126. return $this->routes[$name];
  127. }
  128. }
  129. /**
  130. * Removes a route by name.
  131. *
  132. * @param string $name The route name
  133. */
  134. public function remove($name)
  135. {
  136. if (isset($this->routes[$name])) {
  137. unset($this->routes[$name]);
  138. }
  139. foreach ($this->routes as $routes) {
  140. if ($routes instanceof RouteCollection) {
  141. $routes->remove($name);
  142. }
  143. }
  144. }
  145. /**
  146. * Adds a route collection to the current set of routes (at the end of the current set).
  147. *
  148. * @param RouteCollection $collection A RouteCollection instance
  149. * @param string $prefix An optional prefix to add before each pattern of the route collection
  150. * @param array $defaults An array of default values
  151. * @param array $requirements An array of requirements
  152. *
  153. * @api
  154. */
  155. public function addCollection(RouteCollection $collection, $prefix = '', $defaults = array(), $requirements = array())
  156. {
  157. $collection->setParent($this);
  158. $collection->addPrefix($prefix, $defaults, $requirements);
  159. // remove all routes with the same name in all existing collections
  160. foreach (array_keys($collection->all()) as $name) {
  161. $this->remove($name);
  162. }
  163. $this->routes[] = $collection;
  164. }
  165. /**
  166. * Adds a prefix to all routes in the current set.
  167. *
  168. * @param string $prefix An optional prefix to add before each pattern of the route collection
  169. * @param array $defaults An array of default values
  170. * @param array $requirements An array of requirements
  171. *
  172. * @api
  173. */
  174. public function addPrefix($prefix, $defaults = array(), $requirements = array())
  175. {
  176. // a prefix must not end with a slash
  177. $prefix = rtrim($prefix, '/');
  178. if (!$prefix) {
  179. return;
  180. }
  181. // a prefix must start with a slash
  182. if ('/' !== $prefix[0]) {
  183. $prefix = '/'.$prefix;
  184. }
  185. $this->prefix = $prefix.$this->prefix;
  186. foreach ($this->routes as $name => $route) {
  187. if ($route instanceof RouteCollection) {
  188. $route->addPrefix($prefix, $defaults, $requirements);
  189. } else {
  190. $route->setPattern($prefix.$route->getPattern());
  191. $route->addDefaults($defaults);
  192. $route->addRequirements($requirements);
  193. }
  194. }
  195. }
  196. public function getPrefix()
  197. {
  198. return $this->prefix;
  199. }
  200. /**
  201. * Returns an array of resources loaded to build this collection.
  202. *
  203. * @return ResourceInterface[] An array of resources
  204. */
  205. public function getResources()
  206. {
  207. $resources = $this->resources;
  208. foreach ($this as $routes) {
  209. if ($routes instanceof RouteCollection) {
  210. $resources = array_merge($resources, $routes->getResources());
  211. }
  212. }
  213. return array_unique($resources);
  214. }
  215. /**
  216. * Adds a resource for this collection.
  217. *
  218. * @param ResourceInterface $resource A resource instance
  219. */
  220. public function addResource(ResourceInterface $resource)
  221. {
  222. $this->resources[] = $resource;
  223. }
  224. }