├── .gitignore
├── README.md
├── composer.json
└── src
└── Router.php
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | phpunit.phar
3 | /vendor
4 | composer.phar
5 | composer.lock
6 | *.sublime-project
7 | *.sublime-workspace
8 | *.project
9 | /nbproject
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | PHP Router
2 | ==========
3 |
4 | The Laravel router, for use outside of the Laravel framework.
5 |
6 | Installation
7 | ------------
8 |
9 | Add the package to your `composer.json` and run `composer update`.
10 |
11 | {
12 | "require": {
13 | "seytar/php-router": "1.0.x-stable"
14 | }
15 | }
16 |
17 | Usage
18 | -----
19 |
20 | To start using the router you will need to bootstrap it like this:
21 |
22 | require 'vendor/autoload.php';
23 |
24 | use Seytar\Routing\Router;
25 |
26 | Router::bootstrap(function($ex) {
27 | header('Content-Type: text/html; charset=utf-8');
28 | echo '404 - Page Not Found';
29 | });
30 |
31 | Once this has been done, you can define any route like you would in Laravel:
32 |
33 | Route::get('/', function()
34 | {
35 | echo 'Hello world.';
36 | });
37 |
38 | The bootstrap process will check if there is a `routes.php` file in your application, and will automatically load it for you. It will also register a shutdown function that dispatches the current request. If you want to dispatch the current request manually, you can call `Router::dispatch()`.
39 |
40 | The `Request`, `Response`, `Input` and `URL` facades are also available.
41 |
42 | #### Basic GET Route
43 |
44 | Route::get('/', function()
45 | {
46 | return 'Hello World';
47 | });
48 |
49 | #### Basic POST Route
50 |
51 | Route::post('foo/bar', function()
52 | {
53 | return 'Hello World';
54 | });
55 |
56 | #### Registering A Route For Multiple Verbs
57 |
58 | Route::match(array('GET', 'POST'), '/', function()
59 | {
60 | return 'Hello World';
61 | });
62 |
63 | #### Registering A Route Responding To Any HTTP Verb
64 |
65 | Route::any('foo', function()
66 | {
67 | return 'Hello World';
68 | });
69 |
70 | #### Forcing A Route To Be Served Over HTTPS
71 |
72 | Route::get('foo', array('https', function()
73 | {
74 | return 'Must be over HTTPS';
75 | }));
76 |
77 | Often, you will need to generate URLs to your routes, you may do so using the `URL::to` method:
78 |
79 | $url = URL::to('foo');
80 |
81 |
82 | ## Route Parameters
83 |
84 | Route::get('user/{id}', function($id)
85 | {
86 | return 'User '.$id;
87 | });
88 |
89 | #### Optional Route Parameters
90 |
91 | Route::get('user/{name?}', function($name = null)
92 | {
93 | return $name;
94 | });
95 |
96 | #### Optional Route Parameters With Defaults
97 |
98 | Route::get('user/{name?}', function($name = 'John')
99 | {
100 | return $name;
101 | });
102 |
103 | #### Regular Expression Route Constraints
104 |
105 | Route::get('user/{name}', function($name)
106 | {
107 | //
108 | })
109 | ->where('name', '[A-Za-z]+');
110 |
111 | Route::get('user/{id}', function($id)
112 | {
113 | //
114 | })
115 | ->where('id', '[0-9]+');
116 |
117 | #### Passing An Array Of Wheres
118 |
119 | Of course, you may pass an array of constraints when necessary:
120 |
121 | Route::get('user/{id}/{name}', function($id, $name)
122 | {
123 | //
124 | })
125 | ->where(array('id' => '[0-9]+', 'name' => '[a-z]+'))
126 |
127 | #### Defining Global Patterns
128 |
129 | If you would like a route parameter to always be constrained by a given regular expression, you may use the `pattern` method:
130 |
131 | Route::pattern('id', '[0-9]+');
132 |
133 | Route::get('user/{id}', function($id)
134 | {
135 | // Only called if {id} is numeric.
136 | });
137 |
138 | #### Accessing A Route Parameter Value
139 |
140 | If you need to access a route parameter value outside of a route, you may use the `Route::input` method:
141 |
142 | Route::filter('foo', function()
143 | {
144 | if (Route::input('id') == 1)
145 | {
146 | //
147 | }
148 | });
149 |
150 |
151 | ## Route Filters
152 |
153 | Route filters provide a convenient way of limiting access to a given route, which is useful for creating areas of your site which require authentication. There are several filters included in the Laravel framework, including an `auth` filter, an `auth.basic` filter, a `guest` filter, and a `csrf` filter. These are located in the `app/filters.php` file.
154 |
155 | #### Defining A Route Filter
156 |
157 | Route::filter('old', function()
158 | {
159 | if (Input::get('age') < 200)
160 | {
161 | return Redirect::to('home');
162 | }
163 | });
164 |
165 | If the filter returns a response, that response is considered the response to the request and the route will not execute. Any `after` filters on the route are also cancelled.
166 |
167 | #### Attaching A Filter To A Route
168 |
169 | Route::get('user', array('before' => 'old', function()
170 | {
171 | return 'You are over 200 years old!';
172 | }));
173 |
174 | #### Attaching A Filter To A Controller Action
175 |
176 | Route::get('user', array('before' => 'old', 'uses' => 'UserController@showProfile'));
177 |
178 | #### Attaching Multiple Filters To A Route
179 |
180 | Route::get('user', array('before' => 'auth|old', function()
181 | {
182 | return 'You are authenticated and over 200 years old!';
183 | }));
184 |
185 | #### Attaching Multiple Filters Via Array
186 |
187 | Route::get('user', array('before' => array('auth', 'old'), function()
188 | {
189 | return 'You are authenticated and over 200 years old!';
190 | }));
191 |
192 | #### Specifying Filter Parameters
193 |
194 | Route::filter('age', function($route, $request, $value)
195 | {
196 | //
197 | });
198 |
199 | Route::get('user', array('before' => 'age:200', function()
200 | {
201 | return 'Hello World';
202 | }));
203 |
204 | After filters receive a `$response` as the third argument passed to the filter:
205 |
206 | Route::filter('log', function($route, $request, $response)
207 | {
208 | //
209 | });
210 |
211 | #### Pattern Based Filters
212 |
213 | You may also specify that a filter applies to an entire set of routes based on their URI.
214 |
215 | Route::filter('admin', function()
216 | {
217 | //
218 | });
219 |
220 | Route::when('admin/*', 'admin');
221 |
222 | In the example above, the `admin` filter would be applied to all routes beginning with `admin/`. The asterisk is used as a wildcard, and will match any combination of characters.
223 |
224 | You may also constrain pattern filters by HTTP verbs:
225 |
226 | Route::when('admin/*', 'admin', array('post'));
227 |
228 | #### Filter Classes
229 |
230 | For advanced filtering, you may wish to use a class instead of a Closure. Since filter classes are resolved out of the application [IoC Container](/docs/ioc), you will be able to utilize dependency injection in these filters for greater testability.
231 |
232 | #### Registering A Class Based Filter
233 |
234 | Route::filter('foo', 'FooFilter');
235 |
236 | By default, the `filter` method on the `FooFilter` class will be called:
237 |
238 | class FooFilter {
239 |
240 | public function filter()
241 | {
242 | // Filter logic...
243 | }
244 |
245 | }
246 |
247 | If you do not wish to use the `filter` method, just specify another method:
248 |
249 | Route::filter('foo', 'FooFilter@foo');
250 |
251 |
252 | ## Named Routes
253 |
254 | Named routes make referring to routes when generating redirects or URLs more convenient. You may specify a name for a route like so:
255 |
256 | Route::get('user/profile', array('as' => 'profile', function()
257 | {
258 | //
259 | }));
260 |
261 | You may also specify route names for controller actions:
262 |
263 | Route::get('user/profile', array('as' => 'profile', 'uses' => 'UserController@showProfile'));
264 |
265 | Now, you may use the route's name when generating URLs or redirects:
266 |
267 | $url = URL::route('profile');
268 |
269 | $redirect = Redirect::route('profile');
270 |
271 | You may access the name of a route that is running via the `currentRouteName` method:
272 |
273 | $name = Route::currentRouteName();
274 |
275 |
276 | ## Route Groups
277 |
278 | Sometimes you may need to apply filters to a group of routes. Instead of specifying the filter on each route, you may use a route group:
279 |
280 | Route::group(array('before' => 'auth'), function()
281 | {
282 | Route::get('/', function()
283 | {
284 | // Has Auth Filter
285 | });
286 |
287 | Route::get('user/profile', function()
288 | {
289 | // Has Auth Filter
290 | });
291 | });
292 |
293 | You may also use the `namespace` parameter within your `group` array to specify all controllers within that group as being in a given namespace:
294 |
295 | Route::group(array('namespace' => 'Admin'), function()
296 | {
297 | //
298 | });
299 |
300 |
301 | ## Sub-Domain Routing
302 |
303 | Laravel routes are also able to handle wildcard sub-domains, and pass you wildcard parameters from the domain:
304 |
305 | #### Registering Sub-Domain Routes
306 |
307 | Route::group(array('domain' => '{account}.myapp.com'), function()
308 | {
309 |
310 | Route::get('user/{id}', function($account, $id)
311 | {
312 | //
313 | });
314 |
315 | });
316 |
317 |
318 | ## Route Prefixing
319 |
320 | A group of routes may be prefixed by using the `prefix` option in the attributes array of a group:
321 |
322 | Route::group(array('prefix' => 'admin'), function()
323 | {
324 |
325 | Route::get('user', function()
326 | {
327 | //
328 | });
329 |
330 | });
331 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "seytar/php-router",
3 | "description": "The Laravel router, for use outside of the Laravel framework",
4 | "keywords": ["laravel", "router"],
5 | "license": "MIT",
6 | "homepage": "https://github.com/seytar/php-router",
7 | "authors": [
8 | {
9 | "name": "Saadettin Sivaz",
10 | "homepage": "https://github.com/seytar"
11 | }
12 | ],
13 | "require": {
14 | "illuminate/routing": "4.*",
15 | "illuminate/events": "4.*"
16 | },
17 | "autoload": {
18 | "psr-4": {
19 | "Seytar\\Routing\\": "src/"
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Router.php:
--------------------------------------------------------------------------------
1 | 'Seytar\Routing\Router',
41 | 'App' => 'Illuminate\Support\Facades\App',
42 | 'Input' => 'Illuminate\Support\Facades\Input',
43 | 'Redirect' => 'Illuminate\Support\Facades\Redirect',
44 | 'Request' => 'Illuminate\Support\Facades\Request',
45 | 'Response' => 'Illuminate\Support\Facades\Response',
46 | 'Route' => 'Illuminate\Support\Facades\Route',
47 | 'URL' => 'Illuminate\Support\Facades\URL'
48 | );
49 |
50 | /**
51 | * Create a new router instance.
52 | *
53 | * @return void
54 | */
55 | public function __construct()
56 | {
57 | $this->bootstrap();
58 | }
59 |
60 | public static function bootstrap($errorCallbacks)
61 | {
62 | // Only bootstrap once.
63 | if (static::$bootstrapped)
64 | return;
65 |
66 | // Load helper functions.
67 | require_once __DIR__ . '/../../../illuminate/support/Illuminate/Support/helpers.php';
68 |
69 | // Directories.
70 | $basePath = str_finish(realpath(__DIR__ . '/..'), '/');
71 | $controllersDirectory = $basePath . 'Controllers';
72 | $modelsDirectory = $basePath . 'Models';
73 |
74 | // Register the autoloader and add directories.
75 | ClassLoader::register();
76 | ClassLoader::addDirectories(array($controllersDirectory, $modelsDirectory));
77 |
78 | // Instantiate the container.
79 | $app = new Container;
80 | static::$container = $app;
81 |
82 | // Tell facade about the application instance.
83 | Facade::setFacadeApplication($app);
84 |
85 | // Register application instance with container
86 | $app['app'] = $app;
87 |
88 | // Set environment.
89 | $app['env'] = 'production';
90 |
91 | // Enable HTTP Method Override.
92 | Request::enableHttpMethodParameterOverride();
93 |
94 | // Create the request.
95 | $app['request'] = Request::createFromGlobals();
96 |
97 | // Register services.
98 | with(new EventServiceProvider($app))->register();
99 | with(new RoutingServiceProvider($app))->register();
100 |
101 | // Register aliases.
102 | foreach (static::$aliases as $alias => $class)
103 | {
104 | class_alias($class, $alias);
105 | }
106 |
107 | // Load the routes file if it exists.
108 | if (file_exists($basePath . 'routes.php'))
109 | {
110 | require_once $basePath . 'routes.php';
111 | }
112 |
113 | // Dispatch on shutdown.
114 | register_shutdown_function('Seytar\Routing\Router::dispatch', $errorCallbacks);
115 |
116 | // Mark bootstrapped.
117 | static::$bootstrapped = true;
118 | }
119 |
120 | /**
121 | * Dispatch the current request to the application.
122 | *
123 | * @return \Illuminate\Http\Response
124 | */
125 | public static function dispatch($callbacks)
126 | {
127 | // Only dispatch once.
128 | if (static::$dispatched) return;
129 |
130 | // Get the request.
131 | $request = static::$container['request'];
132 |
133 | try {
134 | // Pass the request to the router.
135 | $response = static::$container['router']->dispatch($request);
136 |
137 | // Send the response.
138 | $response->send();
139 | } catch (\Symfony\Component\HttpKernel\Exception\NotFoundHttpException $ex) {
140 | $callback = is_array($callbacks) ? $callbacks['not_found'] : $callbacks;
141 | call_user_func($callback, $ex);
142 | } catch (\Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException $ex) {
143 | $callback = is_array($callbacks) ? $callbacks['not_allowed'] : $callbacks;
144 | call_user_func($callback, $ex);
145 | }
146 |
147 | // Mark as dispatched.
148 | static::$dispatched = true;
149 | }
150 |
151 | /**
152 | * Dynamically pass calls to the router instance.
153 | *
154 | * @param string $method
155 | * @param array $parameters
156 | * @return mixed
157 | */
158 | public function __call($method, $parameters)
159 | {
160 | return call_user_func_array(array(static::$container['router'], $method), $parameters);
161 | }
162 |
163 | }
164 |
--------------------------------------------------------------------------------