web/lib/Zend/Controller/Router/Route/Hostname.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: Hostname.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  * Hostname 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  * @see        http://manuals.rubyonrails.com/read/chapter/65
       
    34  */
       
    35 class Zend_Controller_Router_Route_Hostname extends Zend_Controller_Router_Route_Abstract
       
    36 {
       
    37 
       
    38     protected $_hostVariable   = ':';
       
    39     protected $_regexDelimiter = '#';
       
    40     protected $_defaultRegex   = null;
       
    41 
       
    42     /**
       
    43      * Holds names of all route's pattern variable names. Array index holds a position in host.
       
    44      * @var array
       
    45      */
       
    46     protected $_variables = array();
       
    47 
       
    48     /**
       
    49      * Holds Route patterns for all host parts. In case of a variable it stores it's regex
       
    50      * requirement or null. In case of a static part, it holds only it's direct value.
       
    51      * @var array
       
    52      */
       
    53     protected $_parts = array();
       
    54 
       
    55     /**
       
    56      * Holds user submitted default values for route's variables. Name and value pairs.
       
    57      * @var array
       
    58      */
       
    59     protected $_defaults = array();
       
    60 
       
    61     /**
       
    62      * Holds user submitted regular expression patterns for route's variables' values.
       
    63      * Name and value pairs.
       
    64      * @var array
       
    65      */
       
    66     protected $_requirements = array();
       
    67 
       
    68     /**
       
    69      * Default scheme
       
    70      * @var string
       
    71      */
       
    72     protected $_scheme = null;
       
    73 
       
    74     /**
       
    75      * Associative array filled on match() that holds matched path values
       
    76      * for given variable names.
       
    77      * @var array
       
    78      */
       
    79     protected $_values = array();
       
    80 
       
    81     /**
       
    82      * Current request object
       
    83      *
       
    84      * @var Zend_Controller_Request_Abstract
       
    85      */
       
    86     protected $_request;
       
    87 
       
    88     /**
       
    89      * Helper var that holds a count of route pattern's static parts
       
    90      * for validation
       
    91      * @var int
       
    92      */
       
    93     private $_staticCount = 0;
       
    94 
       
    95     /**
       
    96      * Set the request object
       
    97      *
       
    98      * @param  Zend_Controller_Request_Abstract|null $request
       
    99      * @return void
       
   100      */
       
   101     public function setRequest(Zend_Controller_Request_Abstract $request = null)
       
   102     {
       
   103         $this->_request = $request;
       
   104     }
       
   105 
       
   106     /**
       
   107      * Get the request object
       
   108      *
       
   109      * @return Zend_Controller_Request_Abstract $request
       
   110      */
       
   111     public function getRequest()
       
   112     {
       
   113         if ($this->_request === null) {
       
   114             require_once 'Zend/Controller/Front.php';
       
   115             $this->_request = Zend_Controller_Front::getInstance()->getRequest();
       
   116         }
       
   117 
       
   118         return $this->_request;
       
   119     }
       
   120 
       
   121     /**
       
   122      * Instantiates route based on passed Zend_Config structure
       
   123      *
       
   124      * @param Zend_Config $config Configuration object
       
   125      */
       
   126     public static function getInstance(Zend_Config $config)
       
   127     {
       
   128         $reqs   = ($config->reqs instanceof Zend_Config) ? $config->reqs->toArray() : array();
       
   129         $defs   = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array();
       
   130         $scheme = (isset($config->scheme)) ? $config->scheme : null;
       
   131         return new self($config->route, $defs, $reqs, $scheme);
       
   132     }
       
   133 
       
   134     /**
       
   135      * Prepares the route for mapping by splitting (exploding) it
       
   136      * to a corresponding atomic parts. These parts are assigned
       
   137      * a position which is later used for matching and preparing values.
       
   138      *
       
   139      * @param string $route Map used to match with later submitted hostname
       
   140      * @param array  $defaults Defaults for map variables with keys as variable names
       
   141      * @param array  $reqs Regular expression requirements for variables (keys as variable names)
       
   142      * @param string $scheme
       
   143      */
       
   144     public function __construct($route, $defaults = array(), $reqs = array(), $scheme = null)
       
   145     {
       
   146         $route               = trim($route, '.');
       
   147         $this->_defaults     = (array) $defaults;
       
   148         $this->_requirements = (array) $reqs;
       
   149         $this->_scheme       = $scheme;
       
   150 
       
   151         if ($route != '') {
       
   152             foreach (explode('.', $route) as $pos => $part) {
       
   153                 if (substr($part, 0, 1) == $this->_hostVariable) {
       
   154                     $name = substr($part, 1);
       
   155                     $this->_parts[$pos] = (isset($reqs[$name]) ? $reqs[$name] : $this->_defaultRegex);
       
   156                     $this->_variables[$pos] = $name;
       
   157                 } else {
       
   158                     $this->_parts[$pos] = $part;
       
   159                     $this->_staticCount++;
       
   160                 }
       
   161             }
       
   162         }
       
   163     }
       
   164 
       
   165     /**
       
   166      * Matches a user submitted path with parts defined by a map. Assigns and
       
   167      * returns an array of variables on a successful match.
       
   168      *
       
   169      * @param Zend_Controller_Request_Http $request Request to get the host from
       
   170      * @return array|false An array of assigned values or a false on a mismatch
       
   171      */
       
   172     public function match($request)
       
   173     {
       
   174         // Check the scheme if required
       
   175         if ($this->_scheme !== null) {
       
   176             $scheme = $request->getScheme();
       
   177 
       
   178             if ($scheme !== $this->_scheme) {
       
   179                 return false;
       
   180             }
       
   181         }
       
   182 
       
   183         // Get the host and remove unnecessary port information
       
   184         $host = $request->getHttpHost();
       
   185         if (preg_match('#:\d+$#', $host, $result) === 1) {
       
   186             $host = substr($host, 0, -strlen($result[0]));
       
   187         }
       
   188 
       
   189         $hostStaticCount = 0;
       
   190         $values = array();
       
   191 
       
   192         $host = trim($host, '.');
       
   193 
       
   194         if ($host != '') {
       
   195             $host = explode('.', $host);
       
   196 
       
   197             foreach ($host as $pos => $hostPart) {
       
   198                 // Host is longer than a route, it's not a match
       
   199                 if (!array_key_exists($pos, $this->_parts)) {
       
   200                     return false;
       
   201                 }
       
   202 
       
   203                 $name = isset($this->_variables[$pos]) ? $this->_variables[$pos] : null;
       
   204                 $hostPart = urldecode($hostPart);
       
   205 
       
   206                 // If it's a static part, match directly
       
   207                 if ($name === null && $this->_parts[$pos] != $hostPart) {
       
   208                     return false;
       
   209                 }
       
   210 
       
   211                 // If it's a variable with requirement, match a regex. If not - everything matches
       
   212                 if ($this->_parts[$pos] !== null && !preg_match($this->_regexDelimiter . '^' . $this->_parts[$pos] . '$' . $this->_regexDelimiter . 'iu', $hostPart)) {
       
   213                     return false;
       
   214                 }
       
   215 
       
   216                 // If it's a variable store it's value for later
       
   217                 if ($name !== null) {
       
   218                     $values[$name] = $hostPart;
       
   219                 } else {
       
   220                     $hostStaticCount++;
       
   221                 }
       
   222             }
       
   223         }
       
   224 
       
   225         // Check if all static mappings have been matched
       
   226         if ($this->_staticCount != $hostStaticCount) {
       
   227             return false;
       
   228         }
       
   229 
       
   230         $return = $values + $this->_defaults;
       
   231 
       
   232         // Check if all map variables have been initialized
       
   233         foreach ($this->_variables as $var) {
       
   234             if (!array_key_exists($var, $return)) {
       
   235                 return false;
       
   236             }
       
   237         }
       
   238 
       
   239         $this->_values = $values;
       
   240 
       
   241         return $return;
       
   242 
       
   243     }
       
   244 
       
   245     /**
       
   246      * Assembles user submitted parameters forming a hostname defined by this route
       
   247      *
       
   248      * @param  array $data An array of variable and value pairs used as parameters
       
   249      * @param  boolean $reset Whether or not to set route defaults with those provided in $data
       
   250      * @return string Route path with user submitted parameters
       
   251      */
       
   252     public function assemble($data = array(), $reset = false, $encode = false, $partial = false)
       
   253     {
       
   254         $host = array();
       
   255         $flag = false;
       
   256 
       
   257         foreach ($this->_parts as $key => $part) {
       
   258             $name = isset($this->_variables[$key]) ? $this->_variables[$key] : null;
       
   259 
       
   260             $useDefault = false;
       
   261             if (isset($name) && array_key_exists($name, $data) && $data[$name] === null) {
       
   262                 $useDefault = true;
       
   263             }
       
   264 
       
   265             if (isset($name)) {
       
   266                 if (isset($data[$name]) && !$useDefault) {
       
   267                     $host[$key] = $data[$name];
       
   268                     unset($data[$name]);
       
   269                 } elseif (!$reset && !$useDefault && isset($this->_values[$name])) {
       
   270                     $host[$key] = $this->_values[$name];
       
   271                 } elseif (isset($this->_defaults[$name])) {
       
   272                     $host[$key] = $this->_defaults[$name];
       
   273                 } else {
       
   274                     require_once 'Zend/Controller/Router/Exception.php';
       
   275                     throw new Zend_Controller_Router_Exception($name . ' is not specified');
       
   276                 }
       
   277             } else {
       
   278                 $host[$key] = $part;
       
   279             }
       
   280         }
       
   281 
       
   282         $return = '';
       
   283 
       
   284         foreach (array_reverse($host, true) as $key => $value) {
       
   285             if ($flag || !isset($this->_variables[$key]) || $value !== $this->getDefault($this->_variables[$key]) || $partial) {
       
   286                 if ($encode) $value = urlencode($value);
       
   287                 $return = '.' . $value . $return;
       
   288                 $flag = true;
       
   289             }
       
   290         }
       
   291 
       
   292         $url = trim($return, '.');
       
   293 
       
   294         if ($this->_scheme !== null) {
       
   295             $scheme = $this->_scheme;
       
   296         } else {
       
   297             $request = $this->getRequest();
       
   298             if ($request instanceof Zend_Controller_Request_Http) {
       
   299                 $scheme = $request->getScheme();
       
   300             } else {
       
   301                 $scheme = 'http';
       
   302             }
       
   303         }
       
   304 
       
   305         $hostname = implode('.', $host);
       
   306         $url      = $scheme . '://' . $url;
       
   307 
       
   308         return $url;
       
   309     }
       
   310 
       
   311     /**
       
   312      * Return a single parameter of route's defaults
       
   313      *
       
   314      * @param string $name Array key of the parameter
       
   315      * @return string Previously set default
       
   316      */
       
   317     public function getDefault($name) {
       
   318         if (isset($this->_defaults[$name])) {
       
   319             return $this->_defaults[$name];
       
   320         }
       
   321         return null;
       
   322     }
       
   323 
       
   324     /**
       
   325      * Return an array of defaults
       
   326      *
       
   327      * @return array Route defaults
       
   328      */
       
   329     public function getDefaults() {
       
   330         return $this->_defaults;
       
   331     }
       
   332 
       
   333     /**
       
   334      * Get all variables which are used by the route
       
   335      *
       
   336      * @return array
       
   337      */
       
   338     public function getVariables()
       
   339     {
       
   340         return $this->_variables;
       
   341     }
       
   342 }