web/lib/Zend/Controller/Router/Route/Regex.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Controller
       
    17  * @subpackage Router
       
    18  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    19  * @version    $Id: Regex.php 20096 2010-01-06 02:05:09Z bkarwin $
       
    20  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    21  */
       
    22 
       
    23 /** Zend_Controller_Router_Route_Abstract */
       
    24 require_once 'Zend/Controller/Router/Route/Abstract.php';
       
    25 
       
    26 /**
       
    27  * Regex Route
       
    28  *
       
    29  * @package    Zend_Controller
       
    30  * @subpackage Router
       
    31  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    32  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    33  */
       
    34 class Zend_Controller_Router_Route_Regex extends Zend_Controller_Router_Route_Abstract
       
    35 {
       
    36     protected $_regex = null;
       
    37     protected $_defaults = array();
       
    38     protected $_reverse = null;
       
    39     protected $_map = array();
       
    40     protected $_values = array();
       
    41 
       
    42     /**
       
    43      * Instantiates route based on passed Zend_Config structure
       
    44      *
       
    45      * @param Zend_Config $config Configuration object
       
    46      */
       
    47     public static function getInstance(Zend_Config $config)
       
    48     {
       
    49         $defs = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array();
       
    50         $map = ($config->map instanceof Zend_Config) ? $config->map->toArray() : array();
       
    51         $reverse = (isset($config->reverse)) ? $config->reverse : null;
       
    52         return new self($config->route, $defs, $map, $reverse);
       
    53     }
       
    54 
       
    55     public function __construct($route, $defaults = array(), $map = array(), $reverse = null)
       
    56     {
       
    57         $this->_regex    = $route;
       
    58         $this->_defaults = (array) $defaults;
       
    59         $this->_map      = (array) $map;
       
    60         $this->_reverse  = $reverse;
       
    61     }
       
    62 
       
    63     public function getVersion() {
       
    64         return 1;
       
    65     }
       
    66 
       
    67     /**
       
    68      * Matches a user submitted path with a previously defined route.
       
    69      * Assigns and returns an array of defaults on a successful match.
       
    70      *
       
    71      * @param  string $path Path used to match against this routing map
       
    72      * @return array|false  An array of assigned values or a false on a mismatch
       
    73      */
       
    74     public function match($path, $partial = false)
       
    75     {
       
    76         if (!$partial) {
       
    77             $path = trim(urldecode($path), '/');
       
    78             $regex = '#^' . $this->_regex . '$#i';
       
    79         } else {
       
    80             $regex = '#^' . $this->_regex . '#i';
       
    81         }
       
    82 
       
    83         $res = preg_match($regex, $path, $values);
       
    84 
       
    85         if ($res === 0) {
       
    86             return false;
       
    87         }
       
    88 
       
    89         if ($partial) {
       
    90             $this->setMatchedPath($values[0]);
       
    91         }
       
    92 
       
    93         // array_filter_key()? Why isn't this in a standard PHP function set yet? :)
       
    94         foreach ($values as $i => $value) {
       
    95             if (!is_int($i) || $i === 0) {
       
    96                 unset($values[$i]);
       
    97             }
       
    98         }
       
    99 
       
   100         $this->_values = $values;
       
   101 
       
   102         $values   = $this->_getMappedValues($values);
       
   103         $defaults = $this->_getMappedValues($this->_defaults, false, true);
       
   104         $return   = $values + $defaults;
       
   105 
       
   106         return $return;
       
   107     }
       
   108 
       
   109     /**
       
   110      * Maps numerically indexed array values to it's associative mapped counterpart.
       
   111      * Or vice versa. Uses user provided map array which consists of index => name
       
   112      * parameter mapping. If map is not found, it returns original array.
       
   113      *
       
   114      * Method strips destination type of keys form source array. Ie. if source array is
       
   115      * indexed numerically then every associative key will be stripped. Vice versa if reversed
       
   116      * is set to true.
       
   117      *
       
   118      * @param  array   $values Indexed or associative array of values to map
       
   119      * @param  boolean $reversed False means translation of index to association. True means reverse.
       
   120      * @param  boolean $preserve Should wrong type of keys be preserved or stripped.
       
   121      * @return array   An array of mapped values
       
   122      */
       
   123     protected function _getMappedValues($values, $reversed = false, $preserve = false)
       
   124     {
       
   125         if (count($this->_map) == 0) {
       
   126             return $values;
       
   127         }
       
   128 
       
   129         $return = array();
       
   130 
       
   131         foreach ($values as $key => $value) {
       
   132             if (is_int($key) && !$reversed) {
       
   133                 if (array_key_exists($key, $this->_map)) {
       
   134                     $index = $this->_map[$key];
       
   135                 } elseif (false === ($index = array_search($key, $this->_map))) {
       
   136                     $index = $key;
       
   137                 }
       
   138                 $return[$index] = $values[$key];
       
   139             } elseif ($reversed) {
       
   140                 $index = $key;
       
   141                 if (!is_int($key)) {
       
   142                     if (array_key_exists($key, $this->_map)) {
       
   143                         $index = $this->_map[$key];
       
   144                     } else {
       
   145                         $index = array_search($key, $this->_map, true);
       
   146                     }
       
   147                 }
       
   148                 if (false !== $index) {
       
   149                     $return[$index] = $values[$key];
       
   150                 }
       
   151             } elseif ($preserve) {
       
   152                 $return[$key] = $value;
       
   153             }
       
   154         }
       
   155 
       
   156         return $return;
       
   157     }
       
   158 
       
   159     /**
       
   160      * Assembles a URL path defined by this route
       
   161      *
       
   162      * @param  array $data An array of name (or index) and value pairs used as parameters
       
   163      * @return string Route path with user submitted parameters
       
   164      */
       
   165     public function assemble($data = array(), $reset = false, $encode = false, $partial = false)
       
   166     {
       
   167         if ($this->_reverse === null) {
       
   168             require_once 'Zend/Controller/Router/Exception.php';
       
   169             throw new Zend_Controller_Router_Exception('Cannot assemble. Reversed route is not specified.');
       
   170         }
       
   171 
       
   172         $defaultValuesMapped  = $this->_getMappedValues($this->_defaults, true, false);
       
   173         $matchedValuesMapped  = $this->_getMappedValues($this->_values, true, false);
       
   174         $dataValuesMapped     = $this->_getMappedValues($data, true, false);
       
   175 
       
   176         // handle resets, if so requested (By null value) to do so
       
   177         if (($resetKeys = array_search(null, $dataValuesMapped, true)) !== false) {
       
   178             foreach ((array) $resetKeys as $resetKey) {
       
   179                 if (isset($matchedValuesMapped[$resetKey])) {
       
   180                     unset($matchedValuesMapped[$resetKey]);
       
   181                     unset($dataValuesMapped[$resetKey]);
       
   182                 }
       
   183             }
       
   184         }
       
   185 
       
   186         // merge all the data together, first defaults, then values matched, then supplied
       
   187         $mergedData = $defaultValuesMapped;
       
   188         $mergedData = $this->_arrayMergeNumericKeys($mergedData, $matchedValuesMapped);
       
   189         $mergedData = $this->_arrayMergeNumericKeys($mergedData, $dataValuesMapped);
       
   190 
       
   191         if ($encode) {
       
   192             foreach ($mergedData as $key => &$value) {
       
   193                 $value = urlencode($value);
       
   194             }
       
   195         }
       
   196 
       
   197         ksort($mergedData);
       
   198 
       
   199         $return = @vsprintf($this->_reverse, $mergedData);
       
   200 
       
   201         if ($return === false) {
       
   202             require_once 'Zend/Controller/Router/Exception.php';
       
   203             throw new Zend_Controller_Router_Exception('Cannot assemble. Too few arguments?');
       
   204         }
       
   205 
       
   206         return $return;
       
   207 
       
   208     }
       
   209 
       
   210     /**
       
   211      * Return a single parameter of route's defaults
       
   212      *
       
   213      * @param string $name Array key of the parameter
       
   214      * @return string Previously set default
       
   215      */
       
   216     public function getDefault($name) {
       
   217         if (isset($this->_defaults[$name])) {
       
   218             return $this->_defaults[$name];
       
   219         }
       
   220     }
       
   221 
       
   222     /**
       
   223      * Return an array of defaults
       
   224      *
       
   225      * @return array Route defaults
       
   226      */
       
   227     public function getDefaults() {
       
   228         return $this->_defaults;
       
   229     }
       
   230 
       
   231     /**
       
   232      * Get all variables which are used by the route
       
   233      *
       
   234      * @return array
       
   235      */
       
   236     public function getVariables()
       
   237     {
       
   238         $variables = array();
       
   239 
       
   240         foreach ($this->_map as $key => $value) {
       
   241             if (is_numeric($key)) {
       
   242                 $variables[] = $value;
       
   243             } else {
       
   244                 $variables[] = $key;
       
   245             }
       
   246         }
       
   247 
       
   248         return $variables;
       
   249     }
       
   250 
       
   251     /**
       
   252      * _arrayMergeNumericKeys() - allows for a strict key (numeric's included) array_merge.
       
   253      * php's array_merge() lacks the ability to merge with numeric keys.
       
   254      *
       
   255      * @param array $array1
       
   256      * @param array $array2
       
   257      * @return array
       
   258      */
       
   259     protected function _arrayMergeNumericKeys(Array $array1, Array $array2)
       
   260     {
       
   261         $returnArray = $array1;
       
   262         foreach ($array2 as $array2Index => $array2Value) {
       
   263             $returnArray[$array2Index] = $array2Value;
       
   264         }
       
   265         return $returnArray;
       
   266     }
       
   267 
       
   268 
       
   269 }