web/lib/Zend/Controller/Router/Route.php
changeset 1230 68c69c656a2c
parent 807 877f952ae2bd
equal deleted inserted replaced
1229:5a6b6e770365 1230:68c69c656a2c
    13  * to license@zend.com so we can send you a copy immediately.
    13  * to license@zend.com so we can send you a copy immediately.
    14  *
    14  *
    15  * @category   Zend
    15  * @category   Zend
    16  * @package    Zend_Controller
    16  * @package    Zend_Controller
    17  * @subpackage Router
    17  * @subpackage Router
    18  * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
    18  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
    19  * @version    $Id: Route.php 24593 2012-01-05 20:35:02Z matthew $
    19  * @version    $Id$
    20  * @license    http://framework.zend.com/license/new-bsd     New BSD License
    20  * @license    http://framework.zend.com/license/new-bsd     New BSD License
    21  */
    21  */
    22 
    22 
    23 /** Zend_Controller_Router_Route_Abstract */
    23 /** Zend_Controller_Router_Route_Abstract */
    24 require_once 'Zend/Controller/Router/Route/Abstract.php';
    24 require_once 'Zend/Controller/Router/Route/Abstract.php';
    26 /**
    26 /**
    27  * Route
    27  * Route
    28  *
    28  *
    29  * @package    Zend_Controller
    29  * @package    Zend_Controller
    30  * @subpackage Router
    30  * @subpackage Router
    31  * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
    31  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
    32  * @license    http://framework.zend.com/license/new-bsd     New BSD License
    32  * @license    http://framework.zend.com/license/new-bsd     New BSD License
    33  * @see        http://manuals.rubyonrails.com/read/chapter/65
    33  * @see        http://manuals.rubyonrails.com/read/chapter/65
    34  */
    34  */
    35 class Zend_Controller_Router_Route extends Zend_Controller_Router_Route_Abstract
    35 class Zend_Controller_Router_Route extends Zend_Controller_Router_Route_Abstract
    36 {
    36 {
       
    37 
    37     /**
    38     /**
    38      * Default translator
    39      * Default translator
    39      *
    40      *
    40      * @var Zend_Translate
    41      * @var Zend_Translate
    41      */
    42      */
    75      * @var array
    76      * @var array
    76      */
    77      */
    77     protected $_translatable = array();
    78     protected $_translatable = array();
    78 
    79 
    79     protected $_urlVariable = ':';
    80     protected $_urlVariable = ':';
       
    81 
    80     protected $_urlDelimiter = self::URI_DELIMITER;
    82     protected $_urlDelimiter = self::URI_DELIMITER;
       
    83 
    81     protected $_regexDelimiter = '#';
    84     protected $_regexDelimiter = '#';
       
    85 
    82     protected $_defaultRegex = null;
    86     protected $_defaultRegex = null;
    83 
    87 
    84     /**
    88     /**
    85      * Holds names of all route's pattern variable names. Array index holds a position in URL.
    89      * Holds names of all route's pattern variable names. Array index holds a position in URL.
       
    90      *
    86      * @var array
    91      * @var array
    87      */
    92      */
    88     protected $_variables = array();
    93     protected $_variables = array();
    89 
    94 
    90     /**
    95     /**
    91      * Holds Route patterns for all URL parts. In case of a variable it stores it's regex
    96      * Holds Route patterns for all URL parts. In case of a variable it stores it's regex
    92      * requirement or null. In case of a static part, it holds only it's direct value.
    97      * requirement or null. In case of a static part, it holds only it's direct value.
    93      * In case of a wildcard, it stores an asterisk (*)
    98      * In case of a wildcard, it stores an asterisk (*)
       
    99      *
    94      * @var array
   100      * @var array
    95      */
   101      */
    96     protected $_parts = array();
   102     protected $_parts = array();
    97 
   103 
    98     /**
   104     /**
    99      * Holds user submitted default values for route's variables. Name and value pairs.
   105      * Holds user submitted default values for route's variables. Name and value pairs.
       
   106      *
   100      * @var array
   107      * @var array
   101      */
   108      */
   102     protected $_defaults = array();
   109     protected $_defaults = array();
   103 
   110 
   104     /**
   111     /**
   105      * Holds user submitted regular expression patterns for route's variables' values.
   112      * Holds user submitted regular expression patterns for route's variables' values.
   106      * Name and value pairs.
   113      * Name and value pairs.
       
   114      *
   107      * @var array
   115      * @var array
   108      */
   116      */
   109     protected $_requirements = array();
   117     protected $_requirements = array();
   110 
   118 
   111     /**
   119     /**
   112      * Associative array filled on match() that holds matched path values
   120      * Associative array filled on match() that holds matched path values
   113      * for given variable names.
   121      * for given variable names.
       
   122      *
   114      * @var array
   123      * @var array
   115      */
   124      */
   116     protected $_values = array();
   125     protected $_values = array();
   117 
   126 
   118     /**
   127     /**
   119      * Associative array filled on match() that holds wildcard variable
   128      * Associative array filled on match() that holds wildcard variable
   120      * names and values.
   129      * names and values.
       
   130      *
   121      * @var array
   131      * @var array
   122      */
   132      */
   123     protected $_wildcardData = array();
   133     protected $_wildcardData = array();
   124 
   134 
   125     /**
   135     /**
   126      * Helper var that holds a count of route pattern's static parts
   136      * Helper var that holds a count of route pattern's static parts
   127      * for validation
   137      * for validation
       
   138      *
   128      * @var int
   139      * @var int
   129      */
   140      */
   130     protected $_staticCount = 0;
   141     protected $_staticCount = 0;
   131 
   142 
   132     public function getVersion() {
   143     public function getVersion()
       
   144     {
   133         return 1;
   145         return 1;
   134     }
   146     }
   135 
   147 
   136     /**
   148     /**
   137      * Instantiates route based on passed Zend_Config structure
   149      * Instantiates route based on passed Zend_Config structure
   138      *
   150      *
   139      * @param Zend_Config $config Configuration object
   151      * @param Zend_Config $config Configuration object
       
   152      * @return Zend_Controller_Router_Route
   140      */
   153      */
   141     public static function getInstance(Zend_Config $config)
   154     public static function getInstance(Zend_Config $config)
   142     {
   155     {
   143         $reqs = ($config->reqs instanceof Zend_Config) ? $config->reqs->toArray() : array();
   156         $reqs = ($config->reqs instanceof Zend_Config) ? $config->reqs->toArray() : array();
   144         $defs = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array();
   157         $defs = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array();
       
   158 
   145         return new self($config->route, $defs, $reqs);
   159         return new self($config->route, $defs, $reqs);
   146     }
   160     }
   147 
   161 
   148     /**
   162     /**
   149      * Prepares the route for mapping by splitting (exploding) it
   163      * Prepares the route for mapping by splitting (exploding) it
   150      * to a corresponding atomic parts. These parts are assigned
   164      * to a corresponding atomic parts. These parts are assigned
   151      * a position which is later used for matching and preparing values.
   165      * a position which is later used for matching and preparing values.
   152      *
   166      *
   153      * @param string $route Map used to match with later submitted URL path
   167      * @param string         $route      Map used to match with later submitted URL path
   154      * @param array $defaults Defaults for map variables with keys as variable names
   168      * @param array          $defaults   Defaults for map variables with keys as variable names
   155      * @param array $reqs Regular expression requirements for variables (keys as variable names)
   169      * @param array          $reqs       Regular expression requirements for variables (keys as variable names)
   156      * @param Zend_Translate $translator Translator to use for this instance
   170      * @param Zend_Translate $translator Translator to use for this instance
   157      */
   171      * @param mixed|null     $locale
   158     public function __construct($route, $defaults = array(), $reqs = array(), Zend_Translate $translator = null, $locale = null)
   172      */
       
   173     public function __construct(
       
   174         $route, $defaults = array(), $reqs = array(), Zend_Translate $translator = null, $locale = null
       
   175     )
   159     {
   176     {
   160         $route               = trim($route, $this->_urlDelimiter);
   177         $route               = trim($route, $this->_urlDelimiter);
   161         $this->_defaults     = (array) $defaults;
   178         $this->_defaults     = (array)$defaults;
   162         $this->_requirements = (array) $reqs;
   179         $this->_requirements = (array)$reqs;
   163         $this->_translator   = $translator;
   180         $this->_translator   = $translator;
   164         $this->_locale       = $locale;
   181         $this->_locale       = $locale;
   165 
   182 
   166         if ($route !== '') {
   183         if ($route !== '') {
   167             foreach (explode($this->_urlDelimiter, $route) as $pos => $part) {
   184             foreach (explode($this->_urlDelimiter, $route) as $pos => $part) {
   197 
   214 
   198     /**
   215     /**
   199      * Matches a user submitted path with parts defined by a map. Assigns and
   216      * Matches a user submitted path with parts defined by a map. Assigns and
   200      * returns an array of variables on a successful match.
   217      * returns an array of variables on a successful match.
   201      *
   218      *
   202      * @param string $path Path used to match against this routing map
   219      * @param string  $path Path used to match against this routing map
       
   220      * @param boolean $partial
       
   221      * @throws Zend_Controller_Router_Exception
   203      * @return array|false An array of assigned values or a false on a mismatch
   222      * @return array|false An array of assigned values or a false on a mismatch
   204      */
   223      */
   205     public function match($path, $partial = false)
   224     public function match($path, $partial = false)
   206     {
   225     {
   207         if ($this->_isTranslated) {
   226         if ($this->_isTranslated) {
   232                 $matchedPath .= $pathPart . $this->_urlDelimiter;
   251                 $matchedPath .= $pathPart . $this->_urlDelimiter;
   233 
   252 
   234                 // If it's a wildcard, get the rest of URL as wildcard data and stop matching
   253                 // If it's a wildcard, get the rest of URL as wildcard data and stop matching
   235                 if ($this->_parts[$pos] == '*') {
   254                 if ($this->_parts[$pos] == '*') {
   236                     $count = count($path);
   255                     $count = count($path);
   237                     for($i = $pos; $i < $count; $i+=2) {
   256                     for ($i = $pos; $i < $count; $i += 2) {
   238                         $var = urldecode($path[$i]);
   257                         $var = urldecode($path[$i]);
   239                         if (!isset($this->_wildcardData[$var]) && !isset($this->_defaults[$var]) && !isset($values[$var])) {
   258                         if (!isset($this->_wildcardData[$var]) && !isset($this->_defaults[$var])
   240                             $this->_wildcardData[$var] = (isset($path[$i+1])) ? urldecode($path[$i+1]) : null;
   259                             && !isset($values[$var])
       
   260                         ) {
       
   261                             $this->_wildcardData[$var] = (isset($path[$i + 1])) ? urldecode($path[$i + 1]) : null;
   241                         }
   262                         }
   242                     }
   263                     }
   243 
   264 
   244                     $matchedPath = implode($this->_urlDelimiter, $path);
   265                     $matchedPath = implode($this->_urlDelimiter, $path);
   245                     break;
   266                     break;
   248                 $name     = isset($this->_variables[$pos]) ? $this->_variables[$pos] : null;
   269                 $name     = isset($this->_variables[$pos]) ? $this->_variables[$pos] : null;
   249                 $pathPart = urldecode($pathPart);
   270                 $pathPart = urldecode($pathPart);
   250 
   271 
   251                 // Translate value if required
   272                 // Translate value if required
   252                 $part = $this->_parts[$pos];
   273                 $part = $this->_parts[$pos];
   253                 if ($this->_isTranslated && (substr($part, 0, 1) === '@' && substr($part, 1, 1) !== '@' && $name === null) || $name !== null && in_array($name, $this->_translatable)) {
   274                 if ($this->_isTranslated
       
   275                     && (substr($part, 0, 1) === '@' && substr($part, 1, 1) !== '@'
       
   276                         && $name === null)
       
   277                     || $name !== null && in_array($name, $this->_translatable)
       
   278                 ) {
   254                     if (substr($part, 0, 1) === '@') {
   279                     if (substr($part, 0, 1) === '@') {
   255                         $part = substr($part, 1);
   280                         $part = substr($part, 1);
   256                     }
   281                     }
   257 
   282 
   258                     if (($originalPathPart = array_search($pathPart, $translateMessages)) !== false) {
   283                     if (($originalPathPart = array_search($pathPart, $translateMessages)) !== false) {
   268                 if ($name === null && $part != $pathPart) {
   293                 if ($name === null && $part != $pathPart) {
   269                     return false;
   294                     return false;
   270                 }
   295                 }
   271 
   296 
   272                 // If it's a variable with requirement, match a regex. If not - everything matches
   297                 // If it's a variable with requirement, match a regex. If not - everything matches
   273                 if ($part !== null && !preg_match($this->_regexDelimiter . '^' . $part . '$' . $this->_regexDelimiter . 'iu', $pathPart)) {
   298                 if ($part !== null
       
   299                     && !preg_match(
       
   300                         $this->_regexDelimiter . '^' . $part . '$' . $this->_regexDelimiter . 'iu', $pathPart
       
   301                     )
       
   302                 ) {
   274                     return false;
   303                     return false;
   275                 }
   304                 }
   276 
   305 
   277                 // If it's a variable store it's value for later
   306                 // If it's a variable store it's value for later
   278                 if ($name !== null) {
   307                 if ($name !== null) {
   303         $this->setMatchedPath(rtrim($matchedPath, $this->_urlDelimiter));
   332         $this->setMatchedPath(rtrim($matchedPath, $this->_urlDelimiter));
   304 
   333 
   305         $this->_values = $values;
   334         $this->_values = $values;
   306 
   335 
   307         return $return;
   336         return $return;
   308 
       
   309     }
   337     }
   310 
   338 
   311     /**
   339     /**
   312      * Assembles user submitted parameters forming a URL path defined by this route
   340      * Assembles user submitted parameters forming a URL path defined by this route
   313      *
   341      *
   314      * @param  array $data An array of variable and value pairs used as parameters
   342      * @param  array   $data  An array of variable and value pairs used as parameters
   315      * @param  boolean $reset Whether or not to set route defaults with those provided in $data
   343      * @param  boolean $reset Whether or not to set route defaults with those provided in $data
       
   344      * @param  boolean $encode
       
   345      * @param  boolean $partial
       
   346      * @throws Zend_Controller_Router_Exception
   316      * @return string Route path with user submitted parameters
   347      * @return string Route path with user submitted parameters
   317      */
   348      */
   318     public function assemble($data = array(), $reset = false, $encode = false, $partial = false)
   349     public function assemble($data = array(), $reset = false, $encode = false, $partial = false)
   319     {
   350     {
   320         if ($this->_isTranslated) {
   351         if ($this->_isTranslated) {
   372                     }
   403                     }
   373 
   404 
   374                     $url[$key] = $part;
   405                     $url[$key] = $part;
   375                 }
   406                 }
   376             } else {
   407             } else {
   377                 if (!$reset) $data += $this->_wildcardData;
   408                 if (!$reset) {
       
   409                     $data += $this->_wildcardData;
       
   410                 }
   378                 $defaults = $this->getDefaults();
   411                 $defaults = $this->getDefaults();
   379                 foreach ($data as $var => $value) {
   412                 foreach ($data as $var => $value) {
   380                     if ($value !== null && (!isset($defaults[$var]) || $value != $defaults[$var])) {
   413                     if ($value !== null && (!isset($defaults[$var]) || $value != $defaults[$var])) {
   381                         $url[$key++] = $var;
   414                         $url[$key++] = $var;
   382                         $url[$key++] = $value;
   415                         $url[$key++] = $value;
   383                         $flag = true;
   416                         $flag        = true;
   384                     }
   417                     }
   385                 }
   418                 }
   386             }
   419             }
   387         }
   420         }
   388 
   421 
   392             $defaultValue = null;
   425             $defaultValue = null;
   393 
   426 
   394             if (isset($this->_variables[$key])) {
   427             if (isset($this->_variables[$key])) {
   395                 $defaultValue = $this->getDefault($this->_variables[$key]);
   428                 $defaultValue = $this->getDefault($this->_variables[$key]);
   396 
   429 
   397                 if ($this->_isTranslated && $defaultValue !== null && isset($this->_translatable[$this->_variables[$key]])) {
   430                 if ($this->_isTranslated && $defaultValue !== null
       
   431                     && isset($this->_translatable[$this->_variables[$key]])
       
   432                 ) {
   398                     $defaultValue = $translator->translate($defaultValue, $locale);
   433                     $defaultValue = $translator->translate($defaultValue, $locale);
   399                 }
   434                 }
   400             }
   435             }
   401 
   436 
   402             if ($flag || $value !== $defaultValue || $partial) {
   437             if ($flag || $value !== $defaultValue || $partial) {
   403                 if ($encode) $value = urlencode($value);
   438                 if ($encode) {
       
   439                     $value = urlencode($value);
       
   440                 }
   404                 $return = $this->_urlDelimiter . $value . $return;
   441                 $return = $this->_urlDelimiter . $value . $return;
   405                 $flag = true;
   442                 $flag   = true;
   406             }
   443             }
   407         }
   444         }
   408 
   445 
   409         return trim($return, $this->_urlDelimiter);
   446         return trim($return, $this->_urlDelimiter);
   410 
       
   411     }
   447     }
   412 
   448 
   413     /**
   449     /**
   414      * Return a single parameter of route's defaults
   450      * Return a single parameter of route's defaults
   415      *
   451      *
   416      * @param string $name Array key of the parameter
   452      * @param string $name Array key of the parameter
   417      * @return string Previously set default
   453      * @return string Previously set default
   418      */
   454      */
   419     public function getDefault($name) {
   455     public function getDefault($name)
       
   456     {
   420         if (isset($this->_defaults[$name])) {
   457         if (isset($this->_defaults[$name])) {
   421             return $this->_defaults[$name];
   458             return $this->_defaults[$name];
   422         }
   459         }
       
   460 
   423         return null;
   461         return null;
   424     }
   462     }
   425 
   463 
   426     /**
   464     /**
   427      * Return an array of defaults
   465      * Return an array of defaults
   428      *
   466      *
   429      * @return array Route defaults
   467      * @return array Route defaults
   430      */
   468      */
   431     public function getDefaults() {
   469     public function getDefaults()
       
   470     {
   432         return $this->_defaults;
   471         return $this->_defaults;
   433     }
   472     }
   434 
   473 
   435     /**
   474     /**
   436      * Get all variables which are used by the route
   475      * Get all variables which are used by the route
   482      */
   521      */
   483     public function getTranslator()
   522     public function getTranslator()
   484     {
   523     {
   485         if ($this->_translator !== null) {
   524         if ($this->_translator !== null) {
   486             return $this->_translator;
   525             return $this->_translator;
   487         } else if (($translator = self::getDefaultTranslator()) !== null) {
       
   488             return $translator;
       
   489         } else {
   526         } else {
   490             try {
   527             if (($translator = self::getDefaultTranslator()) !== null) {
   491                 $translator = Zend_Registry::get('Zend_Translate');
       
   492             } catch (Zend_Exception $e) {
       
   493                 $translator = null;
       
   494             }
       
   495 
       
   496             if ($translator instanceof Zend_Translate) {
       
   497                 return $translator;
   528                 return $translator;
       
   529             } else {
       
   530                 try {
       
   531                     $translator = Zend_Registry::get('Zend_Translate');
       
   532                 } catch (Zend_Exception $e) {
       
   533                     $translator = null;
       
   534                 }
       
   535 
       
   536                 if ($translator instanceof Zend_Translate) {
       
   537                     return $translator;
       
   538                 }
   498             }
   539             }
   499         }
   540         }
   500 
   541 
   501         require_once 'Zend/Controller/Router/Exception.php';
   542         require_once 'Zend/Controller/Router/Exception.php';
   502         throw new Zend_Controller_Router_Exception('Could not find a translator');
   543         throw new Zend_Controller_Router_Exception('Could not find a translator');
   541      */
   582      */
   542     public function getLocale()
   583     public function getLocale()
   543     {
   584     {
   544         if ($this->_locale !== null) {
   585         if ($this->_locale !== null) {
   545             return $this->_locale;
   586             return $this->_locale;
   546         } else if (($locale = self::getDefaultLocale()) !== null) {
       
   547             return $locale;
       
   548         } else {
   587         } else {
   549             try {
   588             if (($locale = self::getDefaultLocale()) !== null) {
   550                 $locale = Zend_Registry::get('Zend_Locale');
       
   551             } catch (Zend_Exception $e) {
       
   552                 $locale = null;
       
   553             }
       
   554 
       
   555             if ($locale !== null) {
       
   556                 return $locale;
   589                 return $locale;
       
   590             } else {
       
   591                 try {
       
   592                     $locale = Zend_Registry::get('Zend_Locale');
       
   593                 } catch (Zend_Exception $e) {
       
   594                     $locale = null;
       
   595                 }
       
   596 
       
   597                 if ($locale !== null) {
       
   598                     return $locale;
       
   599                 }
   557             }
   600             }
   558         }
   601         }
   559 
   602 
   560         return null;
   603         return null;
   561     }
   604     }