<commit_before><?php
/*
 * Created by <NAME> on 2010-02-23.
 * Copyright (c) 2010 <NAME>.
 * All rights reserved.
 */

/**
 * Builds the router cache class.
 */
class Inject_Request_HTTP_URI_RouterBuilder
{
	/**
	 * The class name to use as the compiled router.
	 * 
	 * @var string
	 */
	protected $class_name;
	
	/**
	 * List of files used to create the compiled router.
	 * 
	 * @var array
	 */
	protected $files = array();
	
	/**
	 * List of regular-expression based route objects.
	 * 
	 * @var array
	 */
	protected $regex_routes = array();
	
	/**
	 * List of static route objects.
	 * 
	 * @var array
	 */
	protected $static_routes = array();
	
	/**
	 * Tree for efficient reverse routing of rules.
	 * 
	 * @array
	 */
	protected $reverse_route_tree = array();
	
	/**
	 * Tree for the rules without a controller (and optionally action).
	 * 
	 * @var array
	 */
	protected $reverse_route_dynamic_tree = array('action' => array(), 'no_action' => array());
	
	// ------------------------------------------------------------------------

	/**
	 * Creates a new router builder.
	 * 
	 * @param  string  The classname of the class to generate
	 * @param  array   The files which contains routes
	 */
	public function __construct($class_name, array $files)
	{
		$this->class_name = $class_name;
		$this->files = $files;
		
		// Load the routes
		foreach($this->files as $file)
		{
			include $file;
		}
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Adds a routing rule.
	 * 
	 * The $pattern variable contains a URI match expression which is following
	 * the syntax specified below. If this pattern matches the URI, then the
	 * $options array will be returned to the request object which will use that
	 * data to determine which parameters to show and which controller and action
	 * to run.
	 * 
	 * The $options array have four special keys which will be used by the
	 * request object, all the others will be sent to the controller as parameters.
	 * 
	 * 
	 * The special keys are:
	 * 
	 * - "_controller":  Specifies a controller name to run
	 *                   (automatically adds "Controller_")
	 * 
	 * - "_action":      Specifies an action name to run
	 *                   (automatically adds "action")
	 * 
	 * - "_class":       Specifies a class name to run, this takes precedence
	 *                   over "_controller" and does NOT automatically
	 *                   add "Controller_", so full class names must be used
	 * 
	 * - "_constraints": Used by the captures to change the rules for the
	 *                   content to match, see below for more information
	 * 
	 * 
	 * The $pattern can contain captures, ie. pieces which will "capture" the
	 * matching part of the URI and store it in the parameter with the name of
	 * the capture.
	 * Eg. :id will capture an URI segment (not including "/")
	 * and store it in the parameter called id.
	 * 
	 * 
	 * The captures will override the contents of the $options array if they
	 * use the same name. For example the "id" option (or parameter in this case)
	 * will be overridden in "page(/:id)" if eg. "page/34" is the URI (then the
	 * id parameter will be 34, otherwise it will be whatever it is in the
	 * $options array).
	 * 
	 * So you can for example specify an action to be called if the URI matches
	 * :_controller/foo, and then the controller name will be fetched from the URI.
	 * 
	 * But the _class parameter is not allowed to be used as a capture name for
	 * security reasons, it is not a good idea to let the user specify which class
	 * to call, as that can be anything on the include path.
	 * 
	 * 
	 * Syntax for the pattern:
	 * 
	 * <code>
	 * :foo  = matches a segment into the parameter foo
	 * (bar) = optionally match bar, tries to matches if present
	 * \(    = escaped parenthesis
	 * \)    = escaped closing parenthesis
	 * \:    = escaped match statement
	 * \\:   = escaped escape character followed by a match statement
	 * </code>
	 * 
	 * 
	 * Examples:
	 * 
	 * <code>
	 * page/foo              = matches "page/foo".
	 *                       
	 * page/:id              = matches "welcome/" and then an URI segment which then
	 *                         is stored in the id parameter.
	 *                       
	 * page(/:id)            = matches "welcome" and then an optional "/" followed
	 *                         by a segment which is stored in the id parameter.
	 *                       
	 * (:lang/)page(/:id)    = matches an optional segment whose content will be put
	 *                         in the lang parameter, then "page" and finally a
	 *                         segment which will be put in the id parameter.
	 *                       
	 * \:page:name           = matches ":page" and then the following text goes into
	 *                         the name parameter.
	 * 
	 * users(/:method)(/:id) = matches "users", then optionally a segment whose
	 *                         content is put in method and then another optional
	 *                         segment which is put in id.
	 * 
	 * page(/:id(/:lang))    = matches "page", then optionally "/" followed by data
	 *                         which is put in id, then (if id is populated) an
	 *                         optional "/" + a segment which will be stored in lang.
	 * </code>
	 * 
	 * 
	 * Sometimes you want to be able to adjust what a "segment" is,
	 * by default it is the regular expression for a word (\w) which will
	 * match about anything except for special characters (including : and /).
	 * 
	 * To change that, add the key "_constraints" to the $options parameter
	 * with an array containing capture_name => regular_expression pairs for
	 * the capture matchers you want to replace.
	 * 
	 * 
	 * Example of using _constraints:
	 * 
	 * <code>
	 * $this->matches(
	 *     'rest(/:method)(/:id)',
	 *     array(
	 *         '_controller' => 'rest',
	 *         '_action' => 'handle',
	 *         '_constraints' => array('method' => '[a-z]+', 'id' => '\d+')
	 *         )
	 *     );
	 * </code>
	 * 
	 * This will force the method to be a letter (a-z, at least one char)
	 * and the id to be numeric (0-9).
	 * 
	 * @param  string
	 * @param  array<commit_msg>Minor fixes in the matches() PHPdoc<commit_after><?php
/*
 * Created by <NAME> on 2010-02-23.
 * Copyright (c) 2010 <NAME>.
 * All rights reserved.
 */

/**
 * Builds the router cache class.
 */
class Inject_Request_HTTP_URI_RouterBuilder
{
	/**
	 * The class name to use as the compiled router.
	 * 
	 * @var string
	 */
	protected $class_name;
	
	/**
	 * List of files used to create the compiled router.
	 * 
	 * @var array
	 */
	protected $files = array();
	
	/**
	 * List of regular-expression based route objects.
	 * 
	 * @var array
	 */
	protected $regex_routes = array();
	
	/**
	 * List of static route objects.
	 * 
	 * @var array
	 */
	protected $static_routes = array();
	
	/**
	 * Tree for efficient reverse routing of rules.
	 * 
	 * @array
	 */
	protected $reverse_route_tree = array();
	
	/**
	 * Tree for the rules without a controller (and optionally action).
	 * 
	 * @var array
	 */
	protected $reverse_route_dynamic_tree = array('action' => array(), 'no_action' => array());
	
	// ------------------------------------------------------------------------

	/**
	 * Creates a new router builder.
	 * 
	 * @param  string  The classname of the class to generate
	 * @param  array   The files which contains routes
	 */
	public function __construct($class_name, array $files)
	{
		$this->class_name = $class_name;
		$this->files = $files;
		
		// Load the routes
		foreach($this->files as $file)
		{
			include $file;
		}
	}
	
	// ------------------------------------------------------------------------

	/**
	 * Adds a routing rule.
	 * 
	 * The $pattern variable contains a URI match expression which is following
	 * the syntax specified below. If this pattern matches the URI, then the
	 * $options array will be returned to the request object which will use that
	 * data to determine which parameters to show and which controller and action
	 * to run.
	 * 
	 * The $options array have four special keys which will be used by the
	 * request object, all the others will be sent to the controller as parameters.
	 * 
	 * 
	 * The special keys are:
	 * 
	 * - "_controller":  Specifies a controller name to run
	 *                   (automatically adds "Controller_")
	 * 
	 * - "_action":      Specifies an action name to run
	 *                   (automatically adds "action")
	 * 
	 * - "_class":       Specifies a class name to run, this takes precedence
	 *                   over "_controller" and does NOT automatically
	 *                   add "Controller_", so full class names must be used
	 * 
	 * - "_constraints": Used by the captures to change the rules for the
	 *                   content to match, see below for more information
	 * 
	 * 
	 * The $pattern can contain captures, ie. pieces which will "capture" the
	 * matching part of the URI and store it in the parameter with the name of
	 * the capture.
	 * Eg. :id will capture an URI segment (not including "/")
	 * and store it in the parameter called id.
	 * 
	 * 
	 * The captures will override the contents of the $options array if they
	 * use the same name. For example the "id" option (or parameter in this case)
	 * will be overridden in "page(/:id)" if eg. "page/34" is the URI (then the
	 * id parameter will be 34, if no slash comes after "page" or if there is no
	 * data after the slash, id will be whatever it is in the $options array).
	 * 
	 * So you can for example specify an action to be called if the URI matches
	 * :_controller/foo, and then the controller name will be fetched from the URI.
	 * 
	 * But the _class parameter is not allowed to be used as a capture name for
	 * security reasons, it is not a good idea to let the user specify which class
	 * to call, as that can be anything on the include path.
	 * 
	 * 
	 * Syntax for the pattern:
	 * 
	 * <code>
	 * :foo  = matches a segment into the parameter foo
	 * (bar) = optionally match bar, tries to match if present
	 * \(    = escaped parenthesis
	 * \)    = escaped closing parenthesis
	 * \:    = escaped match statement
	 * \\:   = escaped escape character followed by a match statement
	 * </code>
	 * 
	 * 
	 * Examples:
	 * 
	 * <code>
	 * page/foo              = matches "page/foo".
	 *                       
	 * page/:id              = matches "page/" and then an URI segment which then
	 *                         is stored in the id parameter.
	 *                       
	 * page(/:id)            = matches "page" and then an optional "/" followed
	 *                         by an optional capture which is stored in the id parameter.
	 *                       
	 * (:lang/)page(/:id)    = matches an optional segment whose content will be put
	 *                         in the lang parameter, then "page" and finally an
	 *                         optional segment which will be put in the id parameter.
	 *                       
	 * \:page:name           = matches ":page" and then the following text goes into
	 *                         the name parameter.
	 * 
	 * users(/:method)(/:id) = matches "users", then optionally a segment whose
	 *                         content is put in method and then another optional
	 *                         segment which is put in id.
	 * 
	 * page(/:id(/:lang))    = matches "page", then optionally "/" followed by data
	 *                         which is put in id, then (if id is populated) an
	 *                         optional "/" + a segment which will be stored in lang.
	 * </code>
	 * 
	 * 
	 * Sometimes you want to be able to adjust what a "segment" is,
	 * by default it is the regular expression for a word (\w) which will
	 * match about anything except for special characters (including : and /).
	 * 
	 * To change that, add the key "_constraints" to the $options parameter
	 * with an array containing capture_name => regular_expression pairs for
	 * the capture matchers you want to replace.
	 * 
	 * 
	 * Example of using _constraints:
	 * 
	 * <code>
	 * $this->matches(
	 *     'rest(/:method)(/:id)',
	 *     array(
	 *         '_controller' => 'rest',
	 *         '_action' => 'handle',
	 *         '_constraints' => array('method' => '[a-z]+', 'id' => '\d+')
	 *         )
	 *     );
	 * </code>
	 * 
	 * This will force the method to be a letter (a-z, at least one char)
	 * and the id to be numeric (0-9).
	 * 
	 * 
	 * CAUTION:
	 * Keep in mind that PHP needs escaping of the "\" character in string literals!
	 * 
	 * @param  string
	 * @param  array
{'fraction_non_alphanumeric': 0.11677215189873418, 'fraction_numerical': 0.002848101265822785, 'mean_word_length': 1.9701597744360901, 'pattern_counts': {'":': 10, '<': 21, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5441962', 'n_tokens_mistral': 3673, 'n_tokens_neox': 3161, 'n_words': 1484}