Darya's router is the heart of the framework. It is used to match request paths to a Route
object, which is essentially a set of parameters.
It can also be used to invoke functions or class methods derived from the parameters of matched routes.
This is a detailed set of examples of the different ways the router can be used.
First, you'll want to set up a PHP script as a front controller. If you're using Apache as your web server you could achieve this with a .htaccess
file at the root of your public directory.
RewriteEngine on
# Redirect requests for any non-existing files to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php [L,QSA]
You can define routes in an array when instantiating a router using request paths for keys and route parameters defaults values.
Reserved route parameters are as follows:
namespace
- The namespace to prepend to a matched controllercontroller
- The class to use as a controlleraction
- The anonymous function or controller method to run when the route is dispatchedparams
- Slash-delimited parameters to pass to actions as arguments. This one is always optional and should be used at the end of a route's request path.
Here is an example of instantiating the router with an initial route definition.
The anonymous function becomes the route's action
parameter.
use Darya\Routing\Router;
$router = new Router([
'/' => function () {
return 'Hello world!';
}
]);
/**
* @var Darya\Routing\Route
*/
$route = $router->match('/'); // $route->action === function () { return 'Hello world!'; }
Now that our index.php
receives all requests for any files that don't exist, let's instantiate a router with its first route!
require_once "vendor/darya/framework/autoloader.php";
use Darya\Routing\Router;
$router = new Router([
'/' => ['message' => 'Hello world!'],
'/test' => ['message' => 'Test!']
]);
/**
* @var Darya\Routing\Route
*/
$route = $router->match($_SERVER['REQUEST_URI']);
echo $route->message;
If you navigate to the root directory of your web server, you should see "Hello world!". If you then navigate to /test
you should see 'Test!'.
This example instantiates a router with a couple of base route containing message parameters.
It then matches the current request URL to a route, and prints the matched route's message
property.
When no route is matched using the given request, the match
method returns false
.
If your application is not in your web server's root web directory, but instead in some subdirectory, you can let the router know by setting a base URL.
This is simply a case of using the router's setBaseUrl
method.
$router = new Router([
'/' => ['message' => 'Hello world!'],
'/test' => ['message' => 'Test!']
]);
$router->setBaseUrl('/darya');
echo $router->match('/darya')->message; // Displays 'Hello world!'
echo $router->match('/darya/test')->message; // Displays 'Test!'
Now, provided your .htaccess
and index.php
files are in a subfolder named darya
, the router will work just as it did in the web server's root web directory.
This works simply by removing the given base URL from the beginning of any URLs passed to the match
method.
Darya's router's dispatch
method can be used to run functions when a route is matched.
When you assign a function to a route, it's stored in the route's action
parameter, the same way we set the message
parameter previously.
The dispatch
method simply matches the given request URL to a route and executes its action if one is found. It does some other stuff too but that will be covered later on.
When no route is matched by the given request, the dispatch
method returns null
.
$router = new Router([
'/' => function () {
return 'Hello world!';
}
]);
echo $router->dispatch($_SERVER['REQUEST_URI']);
Darya's router is capable of matching parts of request URLs and setting them as properties on the matched route. If the route already has the matched property, it will be overwritten with the value in the request URL.
You can specify properties in the route's path by prepending a string with the :
character. The following example will print anything after the last /
of the request URL.
$router = new Router([
'/' => ['message' => 'Hello world!'],
'/:message' => ['message' => 'default']
]);
echo $router->match('/test')->message; // Displays 'test'
echo $router->match('/darya')->message; // Displays 'darya'
You can use dynamic parameters with functions too. Matched parameters will be passed in order as arguments to the function. It doesn't matter whether the parameter names match the argument names.
$router = new Router([
'/' => function () {
return 'Hello world!';
},
'/:message' => function ($message) {
return "Hello $message!";
}
]);
echo $router->dispatch($_SERVER['REQUEST_URI']);
With this configuration, visiting /mate
will display Hello mate!
, /dude
will display Hello dude!
and so on.
You can make a URL parameter optional by appending the ?
character. You should
make the function argument optional so that no error if there is no default
value for the parameter.
$router = new Router([
'/:message?' => function ($message = null) {
return $message ? 'Message: ' . $message : 'No message!';
}
]);
To avoid having to echo
the result of your dispatch
call you can use the
respond
method instead. This creates an HTTP response from whatever your
functions return.
$router = new Router([
'/about/:what' => function ($what) {
return "About $what!";
},
'/' => function (){
return 'Hello world!';
}
]);
$router->respond('/about/me'); // 'About me!'
If no route is matched by the request, match
will return false and dispatch
will return null after attempting to call an error handler. You can assign any
callable as the router's error handler.
$router->setErrorHandler(function ($request) {
return 'No route was matched!';
});
You can assign any callable to a route and it will become the route's action parameter.
class MyClass
{
public function myMethod($message) {
return $message ? "Message: $message" : 'No message';
}
}
$router = new Router([
'/:message' => [new MyClass(), 'myMethod']
]);
If you assign a string to the route, it is interpreted as a class name and set
as the route's controller
parameter. When dispatching, the router will then
use the action
parameter as a method to call on the controller
.
The default value for the action parameter is index
.
class MyClass
{
public function index($message) {
return $message ? "Message: $message" : 'No message';
}
}
$router = new Router([
'/:message' => 'MyClass'
]);
Bear in mind that the class will not be instantiated if you assign routes this
way. This is a task for Darya's Dispatcher
class.
You can use dynamic parameters to decide which class method should be run when a route is matched. This is useful for allowing a single class to handle different requests.
class MyClass
{
public function index() {
return 'Index!'
}
public function test() {
return 'Test action!';
}
}
$router = new Router([
'/:action?' => 'MyClass'
]);
$router->respond('/'); // Displays 'Index!'
$router->respond('/test'); // Displays 'Test action!';
You can also suffix a method name with Action and it will still be matched in
the same way. This is useful in the case of using reserved words as action
names. For example, a newAction()
method would be matched by the URL /new
.