router.php 3.08 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
<?php namespace System;

class Router {

	/**
	 * All of the loaded routes.
	 *
	 * @var array
	 */
	public static $routes;

	/**
	 * The named routes that have been found so far.
	 *
	 * @var array
	 */
	public static $names = array();

	/**
	 * Search a set of routes for the route matching a method and URI.
	 *
	 * @param  string  $method
	 * @param  string  $uri
	 * @return Route
	 */
	public static function route($method, $uri)
	{
		// --------------------------------------------------------------
29
		// Force the URI to have a forward slash.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
		// --------------------------------------------------------------
		$uri = ($uri != '/') ? '/'.$uri : $uri;

		static::$routes = require APP_PATH.'routes'.EXT;

		// --------------------------------------------------------------
		// Is there an exact match for the request?
		// --------------------------------------------------------------
		if (isset(static::$routes[$method.' '.$uri]))
		{
			return new Route(static::$routes[$method.' '.$uri]);
		}

		// --------------------------------------------------------------
		// No exact match... check each route individually.
		// --------------------------------------------------------------
		foreach (static::$routes as $keys => $callback)
		{
			// --------------------------------------------------------------
			// Only check routes that have multiple URIs or wildcards.
			// All other routes would have been caught by a literal match.
			// --------------------------------------------------------------
			if (strpos($keys, '(') !== false or strpos($keys, ',') !== false )
			{
				foreach (explode(', ', $keys) as $route)
				{
					$route = str_replace(':num', '[0-9]+', str_replace(':any', '.+', $route));

					if (preg_match('#^'.$route.'$#', $method.' '.$uri))
					{
						return new Route($callback, static::parameters(explode('/', $uri), explode('/', $route)));
					}
				}				
			}
		}
	}

	/**
	 * Find a route by name.
	 *
	 * @param  string  $name
	 * @return array
	 */
	public static function find($name)
	{
		if (array_key_exists($name, static::$names))
		{
			return static::$names[$name];
		}

		$arrayIterator = new \RecursiveArrayIterator(static::$routes);
		$recursiveIterator = new \RecursiveIteratorIterator($arrayIterator);

		foreach ($recursiveIterator as $iterator)
		{
			$route = $recursiveIterator->getSubIterator();

			if ($route['name'] == $name)
			{
				return static::$names[$name] = array($arrayIterator->key() => iterator_to_array($route));
			}
		}
	}

	/**
	 * Get the parameters that should be passed to the route callback.
	 *
	 * @param  array  $uri_segments
	 * @param  array  $route_segments
	 * @return array
	 */
	private static function parameters($uri_segments, $route_segments)
	{
		$parameters = array();

		for ($i = 0; $i < count($route_segments); $i++)
		{
			// --------------------------------------------------------------
			// Any segment wrapped in parentheses is a parameter.
			// --------------------------------------------------------------
			if (strpos($route_segments[$i], '(') === 0)
			{
				$parameters[] = $uri_segments[$i];
			}
		}

		return $parameters;		
	}

}