Skip to content

Basic routing

Andrea Mecchia edited this page Jul 4, 2018 · 5 revisions

Index > HTTP routing > Basic routing


SnooPHP\Http\Router is the class that we use to perform HTTP routing.

To create a router simply create a new object:

$router = new Router();

Routers must be registered with the application using the global function register_router():

$router = register_router(new Router());

The router is merely a container for one or more Route objects. A route is defined by an HTTP method (GET or POST for example), an URL and an action to perform on match. To define a GET route we call Router::get() on our Router object:

$router->get("/home", function() {

	echo "Hello world!"; // Sorry, I had to put it somewhere
});

This route will output Hello world! when the folder /home is requested.

If we want to respond to a form submission we can create a POST route with Router::post() method:

$router->post("/login", function() {

	echo "Logged in!";
});

Similar methods are available for PUT, DELETE and OPTIONS requests.

The Request class

The Request processed by the router is saved in a SnooPHP\Http\Request object that can be accessed with the static method Request::current(). The current request is also passed as the first parameter to the route action:

$router->get("/home", function(Request $request) {});

The Request object exposes a series of methods and properties to retrieve request inputs, request headers and additional informations:

  • Request::input(string|null $input = null, mixed $default = null) is used to retrieve request input. If the name of the input is provided, the corresponding value is returned, otherwise an array with all the inputs is returned. If the specified input is not found, $default is returned (null by default);
  • Request::file(string|null $file = null) returns the specified file (null if not found) or an array of uploaded files;
  • Request::header(string|null $header = null]) returns the specified header value (null if not found) or an array of all the request headers;
  • Request::url() returns the requested URL;
  • Request::method() returns the request method as an uppercase string;
  • Request::time(bool $timestamp = false) returns the time of the request as an ISO string, or as a UNIX timestamp if $timestamp == true

Here's an example of a login route:

$router->post("/login", function(Request $request) {

	$username	= $request->input("username");
	$password	= $request->input("password");
	$stayLogged	= $request->input("stay_logged", false);

	// Check login and start session
	if (Auth::login($username, $password, $stayLogged))
		echo "Logged in!";
	else
		echo "Wrong username or password!";
});

The Response class

While you can use echo and other built-in functions like header() and http_response_code() to respond to a request, the recommended way is to return a SnooPHP\Http\Response object instead:

$router->post("/home", function(Request $request) {

	return new Response("Hello world!", 200);
});

A Response object takes a content, an http code and an array of headers.

The Response class allows you to quickly build different responses using one of this static methods:

  • Response::json(string|array|object $content, int $code = 200) converts your array/object in a JSON string and appends a Content-Type: application/json header to the response;
  • Response::resource(string $file, string|null $type = null, bool $evaluatePhp = false) search for $file in the /resource folder and returns its content. You can specify the content MIME type or let the application decide the most appropriate one. If $evaluatePhp == true the eventual PHP code inside the file is executed and the final content is returned.
  • Response::abort(int $code, string|array|object $content = "") doesn't require a return statement, but rather throws a SnooPHP\Http\AbortRouteException that aborts routing immediately.

Here's the same login example using Response:

$router->post("/login", function(Request $request) {

	$username	= $request->input("username");
	$password	= $request->input("password");
	$stayLogged	= $request->input("stay_logged", false);

	// Check login and start session
	if (Auth::login($username, $password, $stayLogged))
		return Response::json(["status" => "OK", "description" => "logged in"]);
	else
		Response::abort(403, ["status" => "ERROR", "description" => "username or password incorrect"]);
});

You can also return false. In this case, following routes have a possibility to match the request.

Router options

A router has a base, which by default is /. You can specify a different base in the constructor like this:

$router = new Router("/base");

All routes created from this router will inherit this base:

$router->get("home", function() {}); // matches 'GET /base/home'

You can define and register multiple routers with different bases, just keep in mind that when multiple routes matches the request, only the action of the first one is executed, so the order in which you declare your routes matters!

When no route matches the request, an "error action" is executed. You can specify the error action with Router::error():

$router->error(function(Request $request) {

	// Here you cannot use Response::abort()
	return new Response("not found", 404);
});

In case of multiple routers, the error action of the router with the appropriate base is executed: for example, given two routers Router("/abc)" and Router("/123"), for the URL /abc/def/123 the most appropriate router is the former.

It is possible to specify a set of default headers, appended to all responses generated by this router:

$router->defaultHeader([
	"My-Custom-Header"				=> "value",
	"Access-Control-Allow-Origin"	=> "*"
]);

If you want a specific route to ignore this default headers you can set the response property $ignoreDefaultHeaders = true:

$router->error(function(Request $request) {

	$res = new Response("not found", 404);
	$res->ignoreDefaultHeaders = true;
	return $res;
});

Route parameters >

Clone this wiki locally