A very very basic routing class.
Moderator: General Moderators
A very very basic routing class.
I want this feature for my framework.
Route::get('/account/(int)', function() {
Forward('account, array($1))
}
So in reality; ?page=account&memberID=5 would become; /account/5
I would like to see a very small example of how it is done. Manually get URI, explode it by / symbols, handle it accordingly?
I want to see a very basic example of this task. Checked the routing classes in frameworks on github but they are pretty huge. I don't need that. I just want a singlepage class if possible, so I can create mine by referencing to it.
Thanks!
Route::get('/account/(int)', function() {
Forward('account, array($1))
}
So in reality; ?page=account&memberID=5 would become; /account/5
I would like to see a very small example of how it is done. Manually get URI, explode it by / symbols, handle it accordingly?
I want to see a very basic example of this task. Checked the routing classes in frameworks on github but they are pretty huge. I don't need that. I just want a singlepage class if possible, so I can create mine by referencing to it.
Thanks!
Re: A very very basic routing class.
Having done this kind of thing a couple times before, might I suggest this?
1. The first argument is a regular expression you run through preg_match()
2. $dispatch and $matches are so that the callback has access to the things it needs: namely the object that it calls ->Forward() on and the matched data from the regex it gave
---
But you can go even further.
with the default action of the "forward" thing - assuming, of course, that there are other things it could have done. Then 'account' (whatever that is?) gets the array of matches from the regex but now the ID in there is named "memberID". It does require you to know a little bit more about regular expressions but it saves you from writing a lot of interstitial code.
Code: Select all
Route::add('/account/(\d+)', function($dispatch, $matches) {
$dispatch->Forward('account', array($matches[1]));
});Code: Select all
// example data
$url = '/account/5';
$test = '/account/(\d+)';
// here's how you use them
if (preg_match("#^{$test}$#", $url, $matches)) {
// matched. now send $matches to the callback function
} else {
// did not match. try something else
}---
But you can go even further.
Code: Select all
Route::add('/account/(?P<memberID>\d+)', 'account');
Last edited by requinix on Sat Mar 30, 2013 6:08 pm, edited 1 time in total.
Reason: changed regex delimiters
Reason: changed regex delimiters
Re: A very very basic routing class.
How do we get the $url and $test values, $_SERVER['REQUEST_URI']? Also, does the URI depends on platform (like directory differences (/ and \\) between unix and win) or always returns the correct URI?
Re: A very very basic routing class.
Look in $_SERVER. You can use the REQUEST_URI but that will also have the query string. And no, the URI will always use forward slashes.
Re: A very very basic routing class.
I made something like this.
It does not call $route->Boo().
A guy on stackoverflow said I should pass a second parameter to get function, (e.g $uri, Closure $closure) but it will be pretty bad looking.
I want to be able to write PHP codes inside my closure, like;
How can I do this?
Code: Select all
//in Route class
function get($uri)
{
if($uri == '/account')
{
return true;
}
else
{
return false;
}
}
function Boo()
{
echo "Boo";
}
//in index.php
$route = new Route();
$route->get('/account', function() use ($route) {
return $route->Boo();
});
A guy on stackoverflow said I should pass a second parameter to get function, (e.g $uri, Closure $closure) but it will be pretty bad looking.
I want to be able to write PHP codes inside my closure, like;
Code: Select all
$route->get('/account', function() use ($route) {
//Do something what you can do without closure, like loading a view file (e.g $view->create('account.tpl');
});Re: A very very basic routing class.
Of course it doesn't call that method: all get() does is return true or false. Seriously. Read the code.
Try more like
Try more like
Code: Select all
//in Route class
function get($uri, $callback)
{
if($uri == '/account')
{
$callback();
return true;
}
else
{
return false;
}
}Re: A very very basic routing class.
Okay but, handling callback inside the get function isn't something I prefer doing. The route class doesn't connect other classes.
For example, if there is a wrong URI given, I would like to print load 404 view, hence use the template model.
index.php
Index.php has access to $template, but Route class is not. (and should not, it is not his purpose to handle template)
For that reason, I want to handle callback in a different scope. Like the scope in index.php itself so I can use $template->loadView('404.tpl'); inside the closure.
Is that not possible with PHP?
For example, if there is a wrong URI given, I would like to print load 404 view, hence use the template model.
index.php
Code: Select all
if($route->get('account') == true)
$controller->Run();
else
$template->loadView('404.tpl');
For that reason, I want to handle callback in a different scope. Like the scope in index.php itself so I can use $template->loadView('404.tpl'); inside the closure.
Is that not possible with PHP?
Re: A very very basic routing class.
I'm sure it is possible, whatever you're trying to say. What's not possible is for the script to behave in a certain way when you specifically do not want to write the code to allow it to behave in the certain way.
How about this angle. Inside index.php what kind of code do you want to write? What should it look like?
How about this angle. Inside index.php what kind of code do you want to write? What should it look like?
Re: A very very basic routing class.
I don't think I can explain myself any clearer than this.
Let's have a look at your example.
We defined a second paramter to get() function to handle callbacks. However;
1. I don't want to define a secondary parameter in every function to handle callbacks. I want to handle them somewhere else. Not inside a function inside a basic routing class.
2. The routing class has no access to other controllers. So get() function cannot take "$this->database->mysql->query" as a callback because Route class has no access to database object. It is out of it's scope.
In short, I want to do something like this:
But without as a secondary parameter to get function. I may make some other functions than get and I have to re-define a callback eachtime.
How else, without using a second parameter named "Closure $closure" in get() function, you can solve the code above?
Let's have a look at your example.
Code: Select all
//in Route class
function get($uri, $callback)
{
if($uri == '/account')
{
$callback();
return true;
}
else
{
return false;
}
}1. I don't want to define a secondary parameter in every function to handle callbacks. I want to handle them somewhere else. Not inside a function inside a basic routing class.
2. The routing class has no access to other controllers. So get() function cannot take "$this->database->mysql->query" as a callback because Route class has no access to database object. It is out of it's scope.
In short, I want to do something like this:
Code: Select all
index.php
$route->get('/account', function() use ($route) //Like in javascript, get('/account') returns true so we can do something inside the closure.
{
$this->database->mysql->query('BOOM BOOM <span style='color:blue' title='I'm naughty, are you naughty?'>smurf</span>');
or
return Template::load('error.tpl');
});
How else, without using a second parameter named "Closure $closure" in get() function, you can solve the code above?
Re: A very very basic routing class.
1. Then don't use callbacks.
2. I don't know why you're saying it needs to pass mysql->query as a callback. That's not what's happening at all.
As for your sample code, unless you're on 5.4+ you can't use $this directly inside a closure. The Template stuff will work. So is that a solution? I still can't tell what the problem is besides you not wanting to pass along a "dispatcher" object from the Route class (something which, if it exists, the router would most certainly have available) to the callback, and that you've changed the desired behavior of this code a few times in this thread.
So as for my earlier question of what you want your index.php code to look like, is
this it? Where is the result of that ::load() going? You've already said the router has no access to dispatchers, controllers, or databases.
FYI in this pattern, which it seems like you're trying very hard to get right, the router class is in charge of figuring out where a request should be handled. That's all. It shouldn't actually be executing the actions - that's the job of a front controller or dispatcher.
2. I don't know why you're saying it needs to pass mysql->query as a callback. That's not what's happening at all.
As for your sample code, unless you're on 5.4+ you can't use $this directly inside a closure. The Template stuff will work. So is that a solution? I still can't tell what the problem is besides you not wanting to pass along a "dispatcher" object from the Route class (something which, if it exists, the router would most certainly have available) to the callback, and that you've changed the desired behavior of this code a few times in this thread.
So as for my earlier question of what you want your index.php code to look like, is
Code: Select all
$route->get('/account', function() use ($route)
{
return Template::load('error.tpl');
});FYI in this pattern, which it seems like you're trying very hard to get right, the router class is in charge of figuring out where a request should be handled. That's all. It shouldn't actually be executing the actions - that's the job of a front controller or dispatcher.
Re: A very very basic routing class.
Well. How does Laravel handle it then?
http://laravel.com/docs/routing
or
Route class only looks for an $action parameter. (In sources of Laravel Route class)
http://laravel.com/docs/routing
Code: Select all
Route::get('/', function()
{
return "Hello World!";
});Code: Select all
Event::listen('404', function()
{
return Response::error('404');
});Re: A very very basic routing class.
Because that there encapsulates routing and controllers. Those functions are the controllers.
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Re: A very very basic routing class.
You could do something like this:
Code: Select all
class Route
{
protected static $routes = array();
public static function get($route, $function)
{
self::$routes[$route] = $function;
}
public static function run($route)
{
if (isset(self::$routes[$route]) && is_callable(self::$routes[$route])) {
call_user_func(self::$routes[$route]);
}
}
}
Route::get('/', function()
{
echo "Hello World!";
});
Route::run('/');(#10850)
Re: A very very basic routing class.
Yeah, things are alot clearer now! Laravel also does something like this, right?Christopher wrote:You could do something like this:Code: Select all
class Route { protected static $routes = array(); public static function get($route, $function) { self::$routes[$route] = $function; } public static function run($route) { if (isset(self::$routes[$route]) && is_callable(self::$routes[$route])) { call_user_func(self::$routes[$route]); } } } Route::get('/', function() { echo "Hello World!"; }); Route::run('/');
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Re: A very very basic routing class.
I haven't looked at the code, so don't know. This is the style of microframeworks. They are for sites that don't have a lot of pages and the pages are fairly simple. For larger sites you want to use Action Controller classes that are loaded on request.Chris30 wrote:Laravel also does something like this, right?
(#10850)