Location: PHPKode > scripts > phprouter > lie2815-phprouter-fe7e229/phprouter/lib/Router.php
<?php

/**
 * @package phprouter
 */

namespace phprouter;

/**
 * Class used to map methods or functions to URIs
 * @package phprouter
 * @see Http
 * @see Response
 */
abstract class Router
{
	/**
	 * Whether the router has been run
	 * @see map()
	 * @see run()
	 * @var boolean
	 * @access private
	 */
	protected static $run = false;

	/**
	 * Routes
	 * First sub-array contains default routes for specific status codes,
	 * second sub-array contains regular routes
	 * @see map()
	 * @see run()
	 * @var array
	 * @access private
	 */
	protected static $routes = array();

	/**
	 * Set a new route
	 * @see $run
	 * @see $routes
	 * @param string $uri URI to bind, starting with "/"
	 * @param callback $callback Callback function to run
	 * @param array|string $methods Method(s) for which the route is set
	 * @throws InvalidArgumentException on bad parameter
	 * @throws LogicException if the router has been run yet
	 */
	static function map( $uri, $callback, $methods = array() )
	{
		if ( self::$run )
		{
			throw new \LogicException( 'The router has been run yet' );
		}

		$methods = array_map( 'strtoupper', (array) $methods );

		if ( $methods === array() )
		{
			$methods = Http::$methods;
		}

		if ( array_values( array_intersect( Http::$methods, $methods ) ) != $methods )
		{
			throw new \InvalidArgumentException( 'Invalid HTTP method' );
		}

		if ( $uri[0] != '/' )
		{
			//
			// RFC 2616, sec. 9.2 states:
			//
			// "If the Request-URI is an asterisk ("*"), the OPTIONS request
			// is intended to apply to the server in general rather than to a
			// specific resource."
			//
			// http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.2
			//
			if ( $methods !== array( 'OPTIONS' ) && $uri == '*' )
			{
				throw new \InvalidArgumentException( 'URI should start with "/"' );
			}
		}

		if ( preg_match( '`^/\:' . Http::$status_codes_regex . '/?$`', $uri, $match ) )
		{
			self::$routes[0][ intval( $match[1] ) ] = array(
				'callback' => $callback,
				'methods'  => $methods
			);
		}
		else
		{
			self::$routes[1][] = array(
				'uri'      => preg_replace( '`/\:(\w+)`', '/(\w+)', $uri ),
				'callback' => $callback,
				'methods'  => $methods
			);
		}
	}

	/**
	 * Run the router
	 * @see $run
	 * @see $routes
	 * @throws LogicException if the router has been run yet
	 */
	static function run()
	{
		if ( self::$run )
		{
			throw new \LogicException( 'The router has been run yet' );
		}

		self::$run = true;
		$has_route = false;

		if ( isset( self::$routes[1] ) )
		{
			foreach ( self::$routes[1] as $route )
			{
				if ( in_array( Request::method(), $route['methods'] ) &&
					   preg_match( '`^' . $route['uri'] . '/?$`', Request::uri(), $parameters ) )
				{
					array_shift( $parameters ); // $parameters[0] is the whole match

					$has_route = array(
						'route' => $route,
						'parameters' => (array) $parameters
					);
				}
			}
		}

		if ( !$has_route )
		{
			Response::status( 404 );

			// if no default route has been defined for 404 HTTP status code
			if ( !isset( self::$routes[0][404] ) )
			{
				Response::header( 'Content-Type', 'text/plain' );
				echo '404 Not Found';
			}
			else
			{
				call_user_func( self::$routes[0][404]['callback'] );
			}
		}
		else
		{
			// start output buffering to catch callback output
			ob_start();

			// this must be the only output till ob_get_contents()
			call_user_func_array( $has_route['route']['callback'], $has_route['parameters'] );

			$buffer = ob_get_contents();

			if ( $buffer == '' )
			{
				ob_end_clean(); // not sure if necessary

				// [if buffer is empty and] no route has been defined for this
				// HTTP status code
				if ( !isset( self::$routes[0][ Response::$status_code ] ) )
				{
					// display a default message only if the HTTP status code
					// isn't 2XX
					if ( Response::$status_code < 200 || Response::$status_code >= 300 )
					{
						Response::header( 'Content-Type', 'text/plain' );
						echo Http::$status_codes[ Response::$status_code ];
					}
				}
				else
				{
					call_user_func( self::$routes[0][ Response::$status_code ]['callback'] );
				}
			}
			else
			{
				ob_end_flush();
			}
		}
	}
}

/* EOF */
Return current item: phprouter