File indexing completed on 2025-01-26 05:24:55
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Controller 0017 * @subpackage Router 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @version $Id$ 0020 * @license http://framework.zend.com/license/new-bsd New BSD License 0021 */ 0022 0023 /** Zend_Controller_Router_Route_Abstract */ 0024 // require_once 'Zend/Controller/Router/Route/Abstract.php'; 0025 0026 /** 0027 * Regex Route 0028 * 0029 * @package Zend_Controller 0030 * @subpackage Router 0031 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0032 * @license http://framework.zend.com/license/new-bsd New BSD License 0033 */ 0034 class Zend_Controller_Router_Route_Regex extends Zend_Controller_Router_Route_Abstract 0035 { 0036 0037 /** 0038 * Regex string 0039 * 0040 * @var string|null 0041 */ 0042 protected $_regex = null; 0043 0044 /** 0045 * Default values for the route (ie. module, controller, action, params) 0046 * 0047 * @var array 0048 */ 0049 protected $_defaults = array(); 0050 0051 /** 0052 * Reverse 0053 * 0054 * @var string|null 0055 */ 0056 protected $_reverse = null; 0057 0058 /** 0059 * Map 0060 * 0061 * @var array 0062 */ 0063 protected $_map = array(); 0064 0065 /** 0066 * Values 0067 * 0068 * @var array 0069 */ 0070 protected $_values = array(); 0071 0072 /** 0073 * Instantiates route based on passed Zend_Config structure 0074 * 0075 * @param Zend_Config $config Configuration object 0076 * @return Zend_Controller_Router_Route_Regex 0077 */ 0078 public static function getInstance(Zend_Config $config) 0079 { 0080 $defs = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array(); 0081 $map = ($config->map instanceof Zend_Config) ? $config->map->toArray() : array(); 0082 $reverse = (isset($config->reverse)) ? $config->reverse : null; 0083 0084 return new self($config->route, $defs, $map, $reverse); 0085 } 0086 0087 /** 0088 * Constructor 0089 * 0090 * @param $route 0091 * @param array $defaults 0092 * @param array $map 0093 * @param null $reverse 0094 */ 0095 public function __construct($route, $defaults = array(), $map = array(), $reverse = null) 0096 { 0097 $this->_regex = $route; 0098 $this->_defaults = (array) $defaults; 0099 $this->_map = (array) $map; 0100 $this->_reverse = $reverse; 0101 } 0102 0103 /** 0104 * Get the version of the route 0105 * 0106 * @return int 0107 */ 0108 public function getVersion() 0109 { 0110 return 1; 0111 } 0112 0113 /** 0114 * Matches a user submitted path with a previously defined route. 0115 * Assigns and returns an array of defaults on a successful match. 0116 * 0117 * @param string $path Path used to match against this routing map 0118 * @return array|false An array of assigned values or a false on a mismatch 0119 */ 0120 public function match($path, $partial = false) 0121 { 0122 if (!$partial) { 0123 $path = trim(urldecode($path), self::URI_DELIMITER); 0124 $regex = '#^' . $this->_regex . '$#i'; 0125 } else { 0126 $regex = '#^' . $this->_regex . '#i'; 0127 } 0128 0129 $res = preg_match($regex, $path, $values); 0130 0131 if ($res === 0) { 0132 return false; 0133 } 0134 0135 if ($partial) { 0136 $this->setMatchedPath($values[0]); 0137 } 0138 0139 // array_filter_key()? Why isn't this in a standard PHP function set yet? :) 0140 foreach ($values as $i => $value) { 0141 if (!is_int($i) || $i === 0) { 0142 unset($values[$i]); 0143 } 0144 } 0145 0146 $this->_values = $values; 0147 0148 $values = $this->_getMappedValues($values); 0149 $defaults = $this->_getMappedValues($this->_defaults, false, true); 0150 $return = $values + $defaults; 0151 0152 return $return; 0153 } 0154 0155 /** 0156 * Maps numerically indexed array values to it's associative mapped counterpart. 0157 * Or vice versa. Uses user provided map array which consists of index => name 0158 * parameter mapping. If map is not found, it returns original array. 0159 * 0160 * Method strips destination type of keys form source array. Ie. if source array is 0161 * indexed numerically then every associative key will be stripped. Vice versa if reversed 0162 * is set to true. 0163 * 0164 * @param array $values Indexed or associative array of values to map 0165 * @param boolean $reversed False means translation of index to association. True means reverse. 0166 * @param boolean $preserve Should wrong type of keys be preserved or stripped. 0167 * @return array An array of mapped values 0168 */ 0169 protected function _getMappedValues($values, $reversed = false, $preserve = false) 0170 { 0171 if (count($this->_map) == 0) { 0172 return $values; 0173 } 0174 0175 $return = array(); 0176 0177 foreach ($values as $key => $value) { 0178 if (is_int($key) && !$reversed) { 0179 if (array_key_exists($key, $this->_map)) { 0180 $index = $this->_map[$key]; 0181 } elseif (false === ($index = array_search($key, $this->_map))) { 0182 $index = $key; 0183 } 0184 $return[$index] = $values[$key]; 0185 } elseif ($reversed) { 0186 $index = $key; 0187 if (!is_int($key)) { 0188 if (array_key_exists($key, $this->_map)) { 0189 $index = $this->_map[$key]; 0190 } else { 0191 $index = array_search($key, $this->_map, true); 0192 } 0193 } 0194 if (false !== $index) { 0195 $return[$index] = $values[$key]; 0196 } 0197 } elseif ($preserve) { 0198 $return[$key] = $value; 0199 } 0200 } 0201 0202 return $return; 0203 } 0204 0205 /** 0206 * Assembles a URL path defined by this route 0207 * 0208 * @param array $data An array of name (or index) and value pairs used as parameters 0209 * @param boolean $reset 0210 * @param boolean $encode 0211 * @param boolean $partial 0212 * @throws Zend_Controller_Router_Exception 0213 * @return string Route path with user submitted parameters 0214 */ 0215 public function assemble($data = array(), $reset = false, $encode = false, $partial = false) 0216 { 0217 if ($this->_reverse === null) { 0218 // require_once 'Zend/Controller/Router/Exception.php'; 0219 throw new Zend_Controller_Router_Exception('Cannot assemble. Reversed route is not specified.'); 0220 } 0221 0222 $defaultValuesMapped = $this->_getMappedValues($this->_defaults, true, false); 0223 $matchedValuesMapped = $this->_getMappedValues($this->_values, true, false); 0224 $dataValuesMapped = $this->_getMappedValues($data, true, false); 0225 0226 // handle resets, if so requested (By null value) to do so 0227 if (($resetKeys = array_search(null, $dataValuesMapped, true)) !== false) { 0228 foreach ((array)$resetKeys as $resetKey) { 0229 if (isset($matchedValuesMapped[$resetKey])) { 0230 unset($matchedValuesMapped[$resetKey]); 0231 unset($dataValuesMapped[$resetKey]); 0232 } 0233 } 0234 } 0235 0236 // merge all the data together, first defaults, then values matched, then supplied 0237 $mergedData = $defaultValuesMapped; 0238 $mergedData = $this->_arrayMergeNumericKeys($mergedData, $matchedValuesMapped); 0239 $mergedData = $this->_arrayMergeNumericKeys($mergedData, $dataValuesMapped); 0240 0241 if ($encode) { 0242 foreach ($mergedData as $key => &$value) { 0243 $value = urlencode($value); 0244 } 0245 } 0246 0247 ksort($mergedData); 0248 0249 $return = @vsprintf($this->_reverse, $mergedData); 0250 0251 if ($return === false) { 0252 // require_once 'Zend/Controller/Router/Exception.php'; 0253 throw new Zend_Controller_Router_Exception('Cannot assemble. Too few arguments?'); 0254 } 0255 0256 return $return; 0257 } 0258 0259 /** 0260 * Return a single parameter of route's defaults 0261 * 0262 * @param string $name Array key of the parameter 0263 * @return string Previously set default 0264 */ 0265 public function getDefault($name) 0266 { 0267 if (isset($this->_defaults[$name])) { 0268 return $this->_defaults[$name]; 0269 } 0270 } 0271 0272 /** 0273 * Return an array of defaults 0274 * 0275 * @return array Route defaults 0276 */ 0277 public function getDefaults() 0278 { 0279 return $this->_defaults; 0280 } 0281 0282 /** 0283 * Get all variables which are used by the route 0284 * 0285 * @return array 0286 */ 0287 public function getVariables() 0288 { 0289 $variables = array(); 0290 0291 foreach ($this->_map as $key => $value) { 0292 if (is_numeric($key)) { 0293 $variables[] = $value; 0294 } else { 0295 $variables[] = $key; 0296 } 0297 } 0298 0299 return $variables; 0300 } 0301 0302 /** 0303 * _arrayMergeNumericKeys() - allows for a strict key (numeric's included) array_merge. 0304 * php's array_merge() lacks the ability to merge with numeric keys. 0305 * 0306 * @param array $array1 0307 * @param array $array2 0308 * @return array 0309 */ 0310 protected function _arrayMergeNumericKeys(Array $array1, Array $array2) 0311 { 0312 $returnArray = $array1; 0313 foreach ($array2 as $array2Index => $array2Value) { 0314 $returnArray[$array2Index] = $array2Value; 0315 } 0316 0317 return $returnArray; 0318 } 0319 }