PageRenderTime 33ms CodeModel.GetById 14ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 1ms

/applications/core/lib/Zend/Controller/Router/Rewrite.php

#
PHP | 455 lines | 214 code | 62 blank | 179 comment | 38 complexity | ec48dfa44221642772d5b3b51ba0857d MD5 | raw file
  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 * @package    Zend_Controller
 16 * @subpackage Router
 17 * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
 18 * @version    $Id: Rewrite.php 14248 2009-03-08 18:51:35Z dasprid $
 19 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 20 */
 21
 22/** Zend_Loader */
 23require_once 'Zend/Loader.php';
 24
 25/** Zend_Controller_Router_Abstract */
 26require_once 'Zend/Controller/Router/Abstract.php';
 27
 28/** Zend_Controller_Router_Route */
 29require_once 'Zend/Controller/Router/Route.php';
 30
 31/**
 32 * Ruby routing based Router.
 33 *
 34 * @package    Zend_Controller
 35 * @subpackage Router
 36 * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
 37 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 38 * @see        http://manuals.rubyonrails.com/read/chapter/65
 39 */
 40class Zend_Controller_Router_Rewrite extends Zend_Controller_Router_Abstract
 41{
 42
 43    /**
 44     * Whether or not to use default routes
 45     * 
 46     * @var boolean
 47     */
 48    protected $_useDefaultRoutes = true;
 49
 50    /**
 51     * Array of routes to match against
 52     * 
 53     * @var array
 54     */
 55    protected $_routes = array();
 56
 57    /**
 58     * Currently matched route
 59     * 
 60     * @var Zend_Controller_Router_Route_Interface
 61     */
 62    protected $_currentRoute = null;
 63
 64    /**
 65     * Global parameters given to all routes
 66     * 
 67     * @var array
 68     */
 69    protected $_globalParams = array();
 70    
 71    /**
 72     * Add default routes which are used to mimic basic router behaviour
 73     * 
 74     * @return Zend_Controller_Router_Rewrite
 75     */
 76    public function addDefaultRoutes()
 77    {
 78        if (!$this->hasRoute('default')) {
 79            $dispatcher = $this->getFrontController()->getDispatcher();
 80            $request = $this->getFrontController()->getRequest();
 81
 82            require_once 'Zend/Controller/Router/Route/Module.php';
 83            $compat = new Zend_Controller_Router_Route_Module(array(), $dispatcher, $request);
 84
 85            $this->_routes = array_merge(array('default' => $compat), $this->_routes);
 86        }
 87        
 88        return $this;
 89    }
 90
 91    /**
 92     * Add route to the route chain
 93     * 
 94     * If route contains method setRequest(), it is initialized with a request object
 95     *
 96     * @param  string                                 $name       Name of the route
 97     * @param  Zend_Controller_Router_Route_Interface $route      Instance of the route
 98     * @return Zend_Controller_Router_Rewrite
 99     */
100    public function addRoute($name, Zend_Controller_Router_Route_Interface $route) 
101    {
102        if (method_exists($route, 'setRequest')) {
103            $route->setRequest($this->getFrontController()->getRequest());
104        }
105        
106        $this->_routes[$name] = $route;
107        
108        return $this;
109    }
110
111    /**
112     * Add routes to the route chain
113     *
114     * @param  array $routes Array of routes with names as keys and routes as values
115     * @return Zend_Controller_Router_Rewrite
116     */
117    public function addRoutes($routes) {
118        foreach ($routes as $name => $route) {
119            $this->addRoute($name, $route);
120        }
121        
122        return $this;
123    }
124
125    /**
126     * Create routes out of Zend_Config configuration
127     *
128     * Example INI:
129     * routes.archive.route = "archive/:year/*"
130     * routes.archive.defaults.controller = archive
131     * routes.archive.defaults.action = show
132     * routes.archive.defaults.year = 2000
133     * routes.archive.reqs.year = "\d+"
134     *
135     * routes.news.type = "Zend_Controller_Router_Route_Static"
136     * routes.news.route = "news"
137     * routes.news.defaults.controller = "news"
138     * routes.news.defaults.action = "list"
139     *
140     * And finally after you have created a Zend_Config with above ini:
141     * $router = new Zend_Controller_Router_Rewrite();
142     * $router->addConfig($config, 'routes');
143     *
144     * @param  Zend_Config $config  Configuration object
145     * @param  string      $section Name of the config section containing route's definitions
146     * @throws Zend_Controller_Router_Exception
147     * @return Zend_Controller_Router_Rewrite
148     */
149    public function addConfig(Zend_Config $config, $section = null)
150    {
151        if ($section !== null) {
152            if ($config->{$section} === null) {
153                require_once 'Zend/Controller/Router/Exception.php';
154                throw new Zend_Controller_Router_Exception("No route configuration in section '{$section}'");
155            }
156            
157            $config = $config->{$section};
158        }
159        
160        foreach ($config as $name => $info) {
161            $route = $this->_getRouteFromConfig($info);
162            
163            if ($route instanceof Zend_Controller_Router_Route_Chain) {
164                if (!isset($info->chain)) {
165                    require_once 'Zend/Controller/Router/Exception.php';
166                    throw new Zend_Controller_Router_Exception("No chain defined");                    
167                }
168                
169                if ($info->chain instanceof Zend_Config) {
170                    $childRouteNames = $info->chain;
171                } else {
172                    $childRouteNames = explode(',', $info->chain);
173                } 
174                    
175                foreach ($childRouteNames as $childRouteName) {
176                    $childRoute = $this->getRoute(trim($childRouteName));
177                    $route->chain($childRoute);
178                }
179                
180                $this->addRoute($name, $route);
181            } elseif (isset($info->chains) && $info->chains instanceof Zend_Config) {
182                $this->_addChainRoutesFromConfig($name, $route, $info->chains);
183            } else {
184                $this->addRoute($name, $route);
185            }
186        }
187
188        return $this;
189    }
190    
191    /**
192     * Get a route frm a config instance
193     *
194     * @param  Zend_Config $info
195     * @return Zend_Controller_Router_Route_Interface
196     */
197    protected function _getRouteFromConfig(Zend_Config $info)
198    {
199        $class = (isset($info->type)) ? $info->type : 'Zend_Controller_Router_Route';
200        Zend_Loader::loadClass($class);
201              
202        $route = call_user_func(array($class, 'getInstance'), $info);
203        
204        if (isset($info->abstract) && $info->abstract && method_exists($route, 'isAbstract')) {
205            $route->isAbstract(true);
206        }
207
208        return $route;
209    }
210    
211    /**
212     * Add chain routes from a config route
213     *
214     * @param  string                                 $name
215     * @param  Zend_Controller_Router_Route_Interface $route
216     * @param  Zend_Config                            $childRoutesInfo
217     * @return void
218     */
219    protected function _addChainRoutesFromConfig($name,
220                                                 Zend_Controller_Router_Route_Interface $route,
221                                                 Zend_Config $childRoutesInfo)
222    {
223        foreach ($childRoutesInfo as $childRouteName => $childRouteInfo) {
224            if (is_string($childRouteInfo)) {
225                $childRouteName = $childRouteInfo;
226                $childRoute     = $this->getRoute($childRouteName);
227            } else {
228                $childRoute = $this->_getRouteFromConfig($childRouteInfo);
229            }
230            
231            if ($route instanceof Zend_Controller_Router_Route_Chain) {
232                $chainRoute = clone $route;
233                $chainRoute->chain($childRoute);
234            } else {
235                $chainRoute = $route->chain($childRoute);
236            }
237            
238            $chainName = $name . '-' . $childRouteName;
239            
240            if (isset($childRouteInfo->chains)) {
241                $this->_addChainRoutesFromConfig($chainName, $chainRoute, $childRouteInfo->chains);
242            } else {
243                $this->addRoute($chainName, $chainRoute);
244            }
245        }
246    }
247
248    /**
249     * Remove a route from the route chain
250     *
251     * @param  string $name Name of the route
252     * @throws Zend_Controller_Router_Exception
253     * @return Zend_Controller_Router_Rewrite
254     */
255    public function removeRoute($name)
256    {
257        if (!isset($this->_routes[$name])) {
258            require_once 'Zend/Controller/Router/Exception.php';
259            throw new Zend_Controller_Router_Exception("Route $name is not defined");
260        }
261        
262        unset($this->_routes[$name]);
263        
264        return $this;
265    }
266
267    /**
268     * Remove all standard default routes
269     *
270     * @param  Zend_Controller_Router_Route_Interface Route
271     * @return Zend_Controller_Router_Rewrite
272     */
273    public function removeDefaultRoutes()
274    {
275        $this->_useDefaultRoutes = false;
276        
277        return $this;
278    }
279
280    /**
281     * Check if named route exists
282     *
283     * @param  string $name Name of the route
284     * @return boolean
285     */
286    public function hasRoute($name)
287    {
288        return isset($this->_routes[$name]);
289    }
290
291    /**
292     * Retrieve a named route
293     *
294     * @param string $name Name of the route
295     * @throws Zend_Controller_Router_Exception
296     * @return Zend_Controller_Router_Route_Interface Route object
297     */
298    public function getRoute($name)
299    {
300        if (!isset($this->_routes[$name])) {
301            require_once 'Zend/Controller/Router/Exception.php';
302            throw new Zend_Controller_Router_Exception("Route $name is not defined");
303        }
304        
305        return $this->_routes[$name];
306    }
307
308    /**
309     * Retrieve a currently matched route
310     *
311     * @throws Zend_Controller_Router_Exception
312     * @return Zend_Controller_Router_Route_Interface Route object
313     */
314    public function getCurrentRoute()
315    {
316        if (!isset($this->_currentRoute)) {
317            require_once 'Zend/Controller/Router/Exception.php';
318            throw new Zend_Controller_Router_Exception("Current route is not defined");
319        }
320        return $this->getRoute($this->_currentRoute);
321    }
322
323    /**
324     * Retrieve a name of currently matched route
325     *
326     * @throws Zend_Controller_Router_Exception
327     * @return Zend_Controller_Router_Route_Interface Route object
328     */
329    public function getCurrentRouteName()
330    {
331        if (!isset($this->_currentRoute)) {
332            require_once 'Zend/Controller/Router/Exception.php';
333            throw new Zend_Controller_Router_Exception("Current route is not defined");
334        }
335        return $this->_currentRoute;
336    }
337
338    /**
339     * Retrieve an array of routes added to the route chain
340     *
341     * @return array All of the defined routes
342     */
343    public function getRoutes()
344    {
345        return $this->_routes;
346    }
347
348    /**
349     * Find a matching route to the current PATH_INFO and inject
350     * returning values to the Request object.
351     *
352     * @throws Zend_Controller_Router_Exception
353     * @return Zend_Controller_Request_Abstract Request object
354     */
355    public function route(Zend_Controller_Request_Abstract $request)
356    {
357        if (!$request instanceof Zend_Controller_Request_Http) {
358            require_once 'Zend/Controller/Router/Exception.php';
359            throw new Zend_Controller_Router_Exception('Zend_Controller_Router_Rewrite requires a Zend_Controller_Request_Http-based request object');
360        }
361
362        if ($this->_useDefaultRoutes) {
363            $this->addDefaultRoutes();
364        }
365
366        // Find the matching route
367        foreach (array_reverse($this->_routes) as $name => $route) {
368            // TODO: Should be an interface method. Hack for 1.0 BC
369            if (method_exists($route, 'isAbstract') && $route->isAbstract()) {
370                continue;
371            }
372            
373            // TODO: Should be an interface method. Hack for 1.0 BC  
374            if (!method_exists($route, 'getVersion') || $route->getVersion() == 1) {
375                $match = $request->getPathInfo();
376            } else {
377                $match = $request;
378            }
379                        
380            if ($params = $route->match($match)) {
381                $this->_setRequestParams($request, $params);
382                $this->_currentRoute = $name;
383                break;
384            }
385        }
386
387        return $request;
388
389    }
390
391    protected function _setRequestParams($request, $params)
392    {
393        foreach ($params as $param => $value) {
394
395            $request->setParam($param, $value);
396
397            if ($param === $request->getModuleKey()) {
398                $request->setModuleName($value);
399            }
400            if ($param === $request->getControllerKey()) {
401                $request->setControllerName($value);
402            }
403            if ($param === $request->getActionKey()) {
404                $request->setActionName($value);
405            }
406
407        }
408    }
409
410    /**
411     * Generates a URL path that can be used in URL creation, redirection, etc.
412     * 
413     * @param  array $userParams Options passed by a user used to override parameters
414     * @param  mixed $name The name of a Route to use
415     * @param  bool $reset Whether to reset to the route defaults ignoring URL params
416     * @param  bool $encode Tells to encode URL parts on output
417     * @throws Zend_Controller_Router_Exception
418     * @return string Resulting absolute URL path
419     */ 
420    public function assemble($userParams, $name = null, $reset = false, $encode = true)
421    {
422        if ($name == null) {
423            try {
424                $name = $this->getCurrentRouteName();
425            } catch (Zend_Controller_Router_Exception $e) {
426                $name = 'default';
427            }
428        }
429        
430        $params = array_merge($this->_globalParams, $userParams);
431        
432        $route = $this->getRoute($name);
433        $url   = $route->assemble($params, $reset, $encode);
434
435        if (!preg_match('|^[a-z]+://|', $url)) {
436            $url = rtrim($this->getFrontController()->getBaseUrl(), '/') . '/' . $url;
437        }
438
439        return $url;
440    }
441    
442    /**
443     * Set a global parameter
444     * 
445     * @param  string $name
446     * @param  mixed $value
447     * @return Zend_Controller_Router_Rewrite
448     */
449    public function setGlobalParam($name, $value)
450    {
451        $this->_globalParams[$name] = $value;
452    
453        return $this;
454    }
455}