/core/classes/framework/route/route.php
PHP | 778 lines | 306 code | 78 blank | 394 comment | 38 complexity | f98070b18d604e8d4e2ad0ccfdce5a76 MD5 | raw file
- <?php
- /**
- *
- * Instant part of routing system
- *
- * @version 1.0
- *
- * @author Sergey Karavay <sergey.karavay@gmail.com>
- */
- class Route
- {
- /**
- *
- * Route keyname
- *
- * @var string
- */
- private $_key = "";
- /**
- * Pattern string for route as it is in configuration
- *
- * @var string
- */
- private $_fullPattern = "";
-
- /**
- * Pattern string for route without parameters
- *
- * @var string
- */
- private $_clearPattern = "";
-
- /**
- *
- * @var array
- */
- private $_clearPatternArray = array();
-
- /**
- *
- * Packet to link with
- *
- * @var string
- */
- private $_packName = "";
- /**
- *
- * Component name for this route
- *
- * @var string
- */
- private $_componentName = "";
-
- /**
- *
- * Manager class name to link with
- *
- * @var string
- */
- private $_controllerName = "";
-
- /**
- *
- * Action to execute within the page. May be empty if page
- * decides everything about actions internally
- *
- * @var string
- */
- private $_action = "";
- /**
- *
- * Array of page parameter names to be passed
- *
- * @var array
- */
- private $_parameters = array();
-
-
- /**
- *
- * Array of parameters that passed through validator
- *
- * @var array
- */
- private $_parametersMatchedValidator = array();
-
- /**
- * Array of validation patterns for variables
- *
- * @var array
- */
- private $_validator = array();
-
-
- /**
- * Array of default variable values
- *
- *@var array
- */
- private $_defaults = array();
- /**
- *
- * HTTP method used to access the page.
- * If not set then it's "GET"
- *
- * @var string
- */
- private $_httpMethod = "";
-
- /**
- *
- * If this route is for ajax calls
- *
- * @var boolean
- */
- private $_ajaxRoute = false;
- /**
- *
- * Defines whether page is in secured area
- *
- * @var bool
- */
- private $_secured = false;
- /**
- * Creates the Route class instance
- *
- * @param string $pattern pattern that matches route
- * @param string $packComponent pack:component pair
- *
- * @example
- *
- * <pre><code>
- *
- * $route = new Route("some name", "page/nested-page/{param1}/{param2}", "main:index", "view");
- *
- * $route->setValidation(array("param1" =>
- * array(Validator::IS_PATTERN_STRING =>
- * array('pattern' => "[abc]+")),
- * "param2" =>
- * array(Validator::IS_NUMERIC =>
- * array(true))));
- *
- * $route->setDefaults(array( "param1" => "abcabc",
- * "param2" => 13));
- *
- * </code></pre>
- *
- * @throws Exception
- *
- * @return Route
- */
- public function __construct($key, $pattern, $packComponent = "")
- {
- $this->_key = strval($key);
-
- $routeParts = array();
-
- $pattern = self::transliterate($pattern);
- if (!is_string($pattern)
- || !is_string($packComponent)
- || (((false == preg_match_all("/{([a-z0-9]+)}|([a-z0-9]+)/i", $pattern, $routeParts))) && ("" !== $pattern)))
- {
- throw new Exception("Wrong variables passed");
- }
- /**
- *
- * for root_part_1/root_part_2/root_part_3/param_1/param_2
- *
- * $routeParts should be:
- *
- * array(3) {
- [0]=>
- array(5) {
- [0]=>
- string(5) "root_part_1"
- [1]=>
- string(5) "root_part_2"
- [2]=>
- string(5) "root_part_3"
- [3]=>
- string(6) "{param_1}"
- [4]=>
- string(6) "{param_2}"
- }
- [1]=>
- array(5) {
- [0]=>
- string(0) ""
- [1]=>
- string(0) ""
- [2]=>
- string(0) ""
- [3]=>
- string(4) "param_1"
- [4]=>
- string(4) "param_2"
- }
- [2]=>
- array(5) {
- [0]=>
- string(5) "root_part_1"
- [1]=>
- string(5) "root_part_2"
- [2]=>
- string(5) "root_part_3"
- [3]=>
- string(0) ""
- [4]=>
- string(0) ""
- }
- }
- */
- if (isset($routeParts[0]))
- $this->_fullPattern = implode("/", array_filter($routeParts[0])) . "/";
- else
- $this->_fullPattern = "/";
-
- if (isset($routeParts[2]))
- $this->_clearPattern = implode("/", array_filter($routeParts[2])) . "/";
- else
- $this->_clearPattern = "/";
- if (strstr($packComponent, Cfg_App::PACK_COMPONENT_SEPARATOR))
- {
- $pageParts = explode(Cfg_App::PACK_COMPONENT_SEPARATOR, $packComponent);
- $this->_packName = $pageParts[0];
- $this->_componentName = $pageParts[1];
- }
- else
- {
- $this->_packName = App::getCurrentPackName();
- $this->_componentName = $packComponent;
- }
- $parameters = array();
- if (preg_match_all("/{([a-z0-9]+)}/i", $pattern, $parameters))
- {
- $this->_parameters = array_values($parameters[1]);
-
- // foreach($this->_parameters as $param)
- // {
- // $this->_defaults[$param] = "";
- // }
- }
- return $this;
- }
-
- /**
- *
- * Returns route as array of it's parts without parameters
- *
- * @return array
- */
- public function getRouteArray()
- {
- if (!$this->_clearPatternArray)
- {
- $this->_clearPatternArray = self::getUrlArray($this->_clearPattern);
- }
-
- return $this->_clearPatternArray;
- }
-
- /**
- *
- * Returns route array depth
- *
- * @return int
- */
- public function getRouteArrayDepth()
- {
- if (!$this->_clearPatternArray)
- {
- $this->getRouteArray();
- }
-
- return count($this->_clearPatternArray);
- }
-
- /**
- *
- * Returns route key
- *
- * @return string
- */
- public function getKey()
- {
- return $this->_key;
- }
-
- /**
- *
- * Returns route pattern without parameters
- *
- * @return string
- */
- public function getClearPattern()
- {
- return $this->_clearPattern;
- }
-
- /**
- *
- * Returns http method, that should be used for route
- *
- * @return string GET | POST
- */
- public function getHttpMethod()
- {
- return $this->_httpMethod ? $this->_httpMethod : "GET";
- }
-
- /**
- *
- * Sets http method to access this route
- *
- */
- public function setHttpMethod($method)
- {
- if (in_array($method, Cfg_App::$HTTP_METHODS))
- {
- $this->_httpMethod = $method;
- }
- else
- {
- trigger_error("\{$method}\ is not within supported http methods", E_USER_NOTICE);
- }
- }
-
- /**
- *
- * Sets the ajaxRoute flag, if $isAjax parameter presents,
- * gets the ajaxRoute flag otherwise
- *
- * @param boolean $isAjax
- * @return boolean
- */
- public function isAjax($isAjax = null)
- {
- if (is_null($isAjax))
- {
- return $this->_ajaxRoute;
- }
- else
- {
- $this->_ajaxRoute = (bool)$isAjax;
- }
- }
-
- /**
- * Sets the secured flag, if $isSecured parameter presents,
- * gets the secured flag otherwise
- *
- * @param boolean $isSecured
- * @return boolean
- */
- public function isSecured($isSecured = null)
- {
- if (is_null($isSecured))
- {
- return $this->_secured;
- }
- else
- {
- $this->_secured = (bool)$isSecured;
- }
- }
-
- /**
- *
- * Returns count of parameters for route
- *
- * @return int
- */
- public function getParametersCount()
- {
- return count($this->_parameters);
- }
-
- /**
- *
- * Returns controller class name
- *
- * @return string
- */
- public function getControllerName()
- {
- if (!$this->_controllerName){
- $this->setControllerName(Cfg_App::getPackOption(Cfg_App::KEY_DEFAULT_CONTROLLER_NAME, $this->getPackName()));
- }
- return $this->_controllerName;
- }
-
- /**
- *
- * @param type $controllerName
- * @return \Route
- */
- public function setControllerName($controllerName)
- {
- if (!preg_match('/controller$/i', $controllerName))
- {
- $controllerName .= 'Controller';
- }
-
- $this->_controllerName = $controllerName;
-
- return $this;
- }
-
- /**
- *
- * Returns component name
- *
- * @return string
- */
- public function getComponentName()
- {
- return $this->_componentName;
- }
-
- /**
- *
- * Sets route's component name
- *
- * @param type $componentName
- * @return \Route
- */
- public function setComponentName($componentName)
- {
- $this->_componentName = $componentName;
-
- return $this;
- }
-
- /**
- *
- * Returns pack name for this route
- *
- * @return string
- */
- public function getPackName()
- {
- return $this->_packName;
- }
- /**
- *
- * Sets the validators for parameter patterns
- *
- * @param array $validators
- *
- * @example
- *
- * <pre><code>
- *
- * $route->setValidation(array(
- * "param1" =>
- * array(Validator::IS_PATTERN_STRING =>
- * array('pattern' => "[abc]+")),
- * "param2" =>
- * array(Validator::IS_NUMERIC =>
- * array(true)))
- * );
- *
- * </code></pre>
- *
- * @throws Exception
- *
- * @return Route
- */
- public function setValidation(array $validators = array())
- {
- foreach($validators as $var => $validatorPattern)
- {
- if (in_array($var, $this->_parameters))
- {
- $this->_validator[$var] = $validatorPattern;
- }
- }
- return $this->_checkConsistency();
- }
-
- /**
- *
- * Return true, if validation enabled
- *
- * @return bool
- */
- public function validationEnabled()
- {
- return (bool)$this->_filter;
- }
-
- /**
- *
- * Returns count of parameters that passed through validation
- *
- * @return int
- */
- public function getParametersMatchedCount()
- {
- return count($this->_parametersMatchedValidator);
- }
-
- /**
- *
- * Returns parameter value associated with passed $key. If wrong parameter passed
- * default value will be returned. If parameter not passed or not filled by defaults null value will be returned then
- *
- * @param type $key
- *
- * @return mixed|null
- */
- public function getParameter($key)
- {
- if (in_array($key, $this->_parameters)){
- if (isset($this->_parametersMatchedValidator[$key])){
- return $this->_parametersMatchedValidator[$key];
- } elseif (isset($this->_defaults[$key])) {
- return $this->_defaults[$key];
- } else {
- return null;
- }
- } else {
- return null;
- }
- }
-
- public function getParameters()
- {
-
- }
-
- /**
- *
- * Returns count of parameters that are not covered by default values
- *
- * @return int count of parameters without defaults
- */
- public function getDefaultsCoverage()
- {
- return count(array_diff($this->_parameters, array_keys($this->_defaults)));
- }
-
- /**
- *
- * Returns count of parameters that have validators
- *
- * @return int count of parameters under validation
- */
- public function getValidationCoverage()
- {
- return count($this->_validator);
- }
- /**
- *
- * Sets the default values for page parameters
- *
- * @param array $defaults
- *
- * @throws Exception
- *
- * @return Route
- */
- public function setDefaults(array $defaults = array())
- {
- foreach($defaults as $var => $defaultValue)
- {
- if (in_array($var, $this->_parameters))
- {
- $this->_defaults[$var] = $defaultValue;
- }
- }
- return $this->_checkConsistency();
- }
-
- /**
- *
- * Sets route controller action
- *
- * @param string $action
- * @return Route
- */
- public function setActionName($action)
- {
- $this->_action = $action;
-
- return $this;
- }
-
- /**
- *
- * Returns action name to be called
- *
- * @return string Action name
- */
- public function getActionName()
- {
- if ($this->_action && is_string($this->_action))
- {
- return $this->_action;
- }
- else
- {
- return Cfg_App::getPackOption(Cfg_App::KEY_DEFAULT_ACTION_NAME, $this->getPackName());
- }
- }
-
- /**
- *
- * Returns calculated difficulty of ValidatorS
- *
- * @return int calculated difficulty of all Validators for this route
- */
- public function getValidationDifficulty()
- {
- return Validator::getValidationDifficulty($this->_validator);
- }
- /**
- *
- * @return Route
- */
- private function _checkConsistency()
- {
- if ($this->_parameters && $this->_validator && $this->_defaults)
- {
- foreach($this->_parameters as $parameter)
- {
- if (isset($this->_defaults[$parameter]) && $this->_defaults[$parameter] &&
- isset($this->_validator[$parameter]))
- {
- if (!Validator::passMultiValidatorValue($this->_defaults[$parameter],
- $this->_validator[$parameter]))
- {
- throw new Exception("Wrong default parameters passed");
- }
- }
- }
- }
- return $this;
- }
-
- /**
- *
- * Validates parameters passed to the route
- *
- * @param array $urlArray
- *
- * @return array [0] => count of parameters passed to script,
- * [1] => count of parameters that passed the validator,
- * [2] => count of parameters that were not filled from defaults array
- */
- public function validateParameters($urlArray)
- {
- $freeParameters = array_values(array_diff($urlArray, $this->getRouteArray()));
- //echo "<br /> free params " .var_dump($urlArray).var_dump($this->getRouteArray()). var_dump($freeParameters) . "<br />";
- $notFilledByDefaultsCount = 0;
- $this->_parametersMatchedValidator = array();
- //parameters passed to script
- $count = $this->getParametersCount() > count($freeParameters) ? count($freeParameters) : $this->getParametersCount();
- $result = true;
- for($i = 0; $i < $count; $i++)
- {
- if (isset($this->_validator[$this->_parameters[$i]]))
- {
- $result &= Validator::passMultiValidatorValue($freeParameters[$i],
- $this->_validator[$this->_parameters[$i]]);
- }
- if ($result)
- {
- $this->_parametersMatchedValidator[$this->_parameters[$i]] = $freeParameters[$i];
- }
- else
- {
- break;
- }
- }
- if ($result && ($count < $this->getParametersCount()))
- {
- $notPassedParameters = array_diff($this->_parameters, array_keys($this->_parametersMatchedValidator));
- $notFilledByDefaultsCount = count(array_diff($notPassedParameters, array_keys($this->_defaults)));
- }
- //var_dump($freeParameters,count($freeParameters),count($this->_parametersMatchedFilter), $notFilledByDefaultsCount);
- return array(count($freeParameters), count($this->_parametersMatchedValidator), $notFilledByDefaultsCount);
- }
-
- /**
- *
- * "Compares" routes; longer routes
- * are more preferable, but route with less parameters
- * is more likely to be used,
- * so it should be closer to the top;
- *
- * @param Route $a
- * @param Route $b
- * @return int
- */
- public static function compare(Route $a, Route $b)
- {
- if ($a->getClearPattern() == $b->getClearPattern())
- {
- return ($a->getParametersCount() < $b->getParametersCount()) ? -1 : 1;
- }
- else
- {
- return ($a->getClearPattern() > $b->getClearPattern()) ? -1 : 1;
- }
- }
-
- /**
- *
- * Returns an array of url parts
- *
- * @example
- * /path1/path2/path3/ => array('path1', 'path2', 'path3')
- *
- * @param string $url url string to be converted to array
- * @return array
- *
- * @throws Exception
- */
- public static function getUrlArray($url)
- {
- if (!is_string($url))
- {
- throw new Exception("Url must be a string");
- }
-
- $url = self::transliterate($url);
-
- $urlParts = array_map('trim', array_filter(explode("/", $url)));
- array_unshift($urlParts, "/");
- return $urlParts;
- }
-
- /**
- *
- * One-way transliteration function for cyrrilic support
- *
- * @param string $text Cyrillic text
- * @return string Transliterated text
- */
- public static function transliterate($text) {
-
- $cyrrilic = array(
- 'а', 'б', 'в', 'г', 'д', 'e', 'ё', 'ж', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', 'п', 'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ч', 'ш', 'щ', 'ъ', 'ы', 'ь', 'э', 'ю', 'я',
- );
- $latin = array(
- 'a', 'b', 'v', 'g', 'd', 'e', 'yo', 'zh', 'z', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'f', 'h', 'c', 'ch', 'sh', 'sht', '', 'y', '', 'e', 'yu', 'ya',
- );
-
- return str_ireplace($cyrrilic, $latin, $text);
- }
- }
- ?>