OSDN Git Service

Modified method name also for config loading
[php-libraries/Router.git] / src / PHPRouter / Router.php
1 <?php
2 /**
3  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14  *
15  * This software consists of voluntary contributions made by many individuals
16  * and is licensed under the MIT license.
17  */
18 namespace PHPRouter;
19
20 use Exception;
21 use PHPRouter\RouteCollection;
22
23 /**
24  * Routing class to match request URL's against given routes and map them to a controller action.
25  */
26 class Router
27 {
28     /**
29     * Array that holds all Route objects
30     * @var array
31     */
32     private $routes = array();
33
34     /**
35      * Array to store named routes in, used for reverse routing.
36      * @var array
37      */
38     private $namedRoutes = array();
39
40     /**
41      * The base REQUEST_URI. Gets prepended to all route url's.
42      * @var string
43      */
44     private $basePath = '';
45
46     /**
47      * @param RouteCollection $collection
48      */
49     public function __construct(RouteCollection $collection)
50     {
51         $this->routes = $collection;
52     }
53
54     /**
55      * Set the base _url - gets prepended to all route _url's.
56      * @param $basePath
57      */
58     public function setBasePath($basePath)
59     {
60         $this->basePath = (string) $basePath;
61     }
62
63     /**
64     * Matches the current request against mapped routes
65     */
66     public function matchCurrentRequest()
67     {
68         $requestMethod = (
69             isset($_POST['_method'])
70             && ($_method = strtoupper($_POST['_method']))
71             && in_array($_method, array('PUT', 'DELETE'))
72         ) ? $_method : $_SERVER['REQUEST_METHOD'];
73
74         $requestUrl = $_SERVER['REQUEST_URI'];
75
76         // strip GET variables from URL
77         if (($pos = strpos($requestUrl, '?')) !== false) {
78             $requestUrl =  substr($requestUrl, 0, $pos);
79         }
80
81         return $this->match($requestUrl, $requestMethod);
82     }
83
84     /**
85      * Match given request _url and request method and see if a route has been defined for it
86      * If so, return route's target
87      * If called multiple times
88      *
89      * @param string $requestUrl
90      * @param string $requestMethod
91      * @return bool
92      */
93     public function match($requestUrl, $requestMethod = 'GET')
94     {
95         foreach ($this->routes->all() as $routes) {
96
97             // compare server request method with route's allowed http methods
98             if (! in_array($requestMethod, (array) $routes->getMethods())) {
99                 continue;
100             }
101
102             // check if request _url matches route regex. if not, return false.
103             if (! preg_match("@^".$this->basePath.$routes->getRegex()."*$@i", $requestUrl, $matches)) {
104                 continue;
105             }
106
107             $params = array();
108
109             if (preg_match_all("/:([\w-%]+)/", $routes->getUrl(), $argument_keys)) {
110
111                 // grab array with matches
112                 $argument_keys = $argument_keys[1];
113
114                 // loop trough parameter names, store matching value in $params array
115                 foreach ($argument_keys as $key => $name) {
116                     if (isset($matches[$key + 1])) {
117                         $params[$name] = $matches[$key + 1];
118                     }
119                 }
120
121             }
122
123             $routes->setParameters($params);
124             $routes->dispatch();
125
126             return $routes;
127         }
128
129         return false;
130     }
131
132
133     /**
134      * Reverse route a named route
135      *
136      * @param $routeName
137      * @param array $params Optional array of parameters to use in URL
138      * @throws Exception
139      *
140      * @internal param string $route_name The name of the route to reverse route.
141      * @return string The url to the route
142      */
143     public function generate($routeName, array $params = array())
144     {
145         // Check if route exists
146         if (! isset($this->namedRoutes[$routeName])) {
147             throw new Exception("No route with the name $routeName has been found.");
148         }
149
150         $route = $this->namedRoutes[$routeName];
151         $url = $route->getUrl();
152
153         // replace route url with given parameters
154         if ($params && preg_match_all("/:(\w+)/", $url, $param_keys)) {
155             // grab array with matches
156             $param_keys = $param_keys[1];
157
158             // loop trough parameter names, store matching value in $params array
159             foreach ($param_keys as $key) {
160                 if (isset($params[$key])) {
161                     $url = preg_replace("/:(\w+)/", $params[$key], $url, 1);
162                 }
163             }
164         }
165
166         return $url;
167     }
168
169
170     /**
171      * Create routes by array, and return a Router object
172      *
173      * @param array $config provide by Config::loadFromFile()
174      * @return Router
175      */
176     public static function parseConfig(array $config)
177     {
178         $collection = new RouteCollection();
179         foreach ($config['routes'] as $name => $route) {
180             $collection->attachRoute(new Route($route[0], array(
181                 '_controller' => str_replace('.', '::', $route[1]),
182                 'methods' => $route[2]
183             )));
184         }
185
186         $router = new Router($collection);
187         if (isset($config['base_path'])) {
188             $router->setBasePath($config['base_path']);
189         }
190
191         return $router;
192     }
193 }