Location: PHPKode > projects > GnomePHP > peec-GnomePHP-b5a360b/gnomephp/mvc/router/Router.php
<?php
namespace gnomephp\mvc\router;

/**
 * Main Router entry point for GnomePHP.
 * 
 * This router is pretty advanced and can handle very specific configuration to more relaxed configuration.
 * @author peec
 *
 */
class Router{
	const REGEXP_LINE = '/\s+|(.*?)\s+(.*?)\s+(.*?)$/';
	const EXTEND_TAG = '/\{extend=([\/a-zA-Z0-9_-]*)\}/';
	/**
	 * List of Rule objects.
	 * @var array
	 */
	private $rules=array();
	
	/**
	 * Copy of $_SERVER object.
	 * Notice: only PATH_INFO and REQUEST_METHOD is needed as keys.
	 * @var unknown_type
	 */
	private $server;
	
	
	private $url;
	
	
	/**
	 * Since its a quite costly operation to generate links based on url, we cache UrlLinks.
	 * 
	 * @var array
	 */
	private $reverseRouteCache = array();
	
	/**
	 * This script REQUEST_METHOD from the server array.
	 * Define array with the element or just pass $_SERVER to it.
	 * 
	 * @param array $server The $_SERVER array.
	 */
	public function __construct($url, $server){
		$this->server = $server;
		$this->url = $url;
		
	}
	
	/**
	 * Sets new current url.
	 */
	public function setUrl($url){
		$this->url = $url;
	}
	
	/**
	 * Gets the URL Path .
	 * eg. www.mysite.com/news/this-is-my-article?var=shownews
	 * will return /news/this-is-my-article
	 */
	protected function getUrl(){
		return $this->url ? $this->url : '/';
	}
	
	/**
	 * Gets the client request type as integer.
	 * @see Router::requestToInt
	 */
	protected function getClientRequest(){
		return isset($this->server['REQUEST_METHOD']) ? $this->requestToInt($this->server['REQUEST_METHOD']) : Rule::R_GET;
	}
	
	
	/**
	 * Adds a new rule to the router.
	 * @param Rule $rule
	 */
	public function addRule($rule){
		$this->rules[] = $rule;
	}
	
	

	/**
	 * Parses a router string config.
	 * Example of string:
	 * -------
	 * # GET /sa Controller.method
	 * GET    	/sa/{<[0-9]+>sd}/{sd2}/?    Controller.method($sd2, $sd)
	 * # Default route.
	 * *   /{controller}/{method}/?    $controller.$method()
	 * -------
	 * @param string $stringConfig
	 */
	public function parse($stringConfig){
		$lines = explode("\n", $stringConfig);
		foreach($lines as $line){
			$line = trim($line);
			$isComment = substr($line, 0, 1) == '#';
			
			// Parser extends.
			$parts = array();
			if (!$isComment && preg_match(Router::EXTEND_TAG, $line, $parts)){
				$extend = $parts[1];
				if (substr($extend, 0, 5) == 'core/'){
					$this->parse(file_get_contents(GNOME_FW_PATH . '/res/config/routes/'.substr($extend, 5).'.conf'));
				}
			}
			
			$parts = array();
			if (!$isComment && preg_match(Router::REGEXP_LINE, $line, $parts) ){
				if (count($parts)==4){
					
					$this->addRule(new Rule($this->requestToInt($parts[1]), $parts[2], $parts[3]));
				}
			}
		}
	}
	
	/**
	 * Returns int of a valid / supported request type.
	 * 
	 * @param string $request GET, POST, or * ( * means all requests )
	 * @throws RouterParseException
	 */
	protected function requestToInt($request){
		switch(strtoupper($request)){
			case 'GET':
				return Rule::R_GET;
				break;
			case 'POST':
				return Rule::R_POST;
				break;
			case '*':
				return Rule::R_ALL;
				break;
			default:
				throw new RouterParseException("Could not parse router string. Unable to solve $request to any of the valid request types.");
		}
	}
	
	/**
	 * Gets the Controller, method and arguments as an array.
	 */
	public function route(){
		foreach($this->rules as $rule){
			if ($r = $rule->validate($this->getClientRequest(), $this->getUrl())){
				return $r;
			}
		}
		return null;
	}

	
	/**
	 * Can reverse engineer a specific $controller, $method and arguments pattern.
	 * 
	 * Will return object of UrlString.
	 * 
	 * 
	 * @param string $controller
	 * @param string $method
	 * @param array $args
	 * @return gnomephp\mvc\string\UrlString
	 */
	public function reverse($controller, $method, $args=array()){
		$uniqueID = md5($controller . $method . var_export($args, true));
		// Does it exist ? 
		if (isset($this->reverseRouteCache[$uniqueID])) return $this->reverseRouteCache[$uniqueID];
		
		// Go thru routes.
		foreach($this->rules as $rule){
			
			if ($url = $rule->reverse($controller, $method, $args)){
				// Cache it!
				$this->reverseRouteCache[$uniqueID] = $url;
				// Return
				return $this->reverseRouteCache[$uniqueID];
			}
		}
		return false;
	}
	
}

Return current item: GnomePHP