sFire PHP Framework

Routing in routes.php

All the routes will be defined in the routes.php. sFire lets you listen to HTTP request based on a given URL. The request will be forwarded to the given module, controller and associated action. From a simple website with just a single page and url to a complete restful API; routes.php is the way to go.

In this section we will handle:

  • Creating the first route
  • Handeling HTTP requests like GET, POST, DELETE, PUT, HEAD, CONNECT, OPTIONS, TRACE and PATCH
  • Grouping routes and prefix URL's
  • Create error routes
  • Using strict and non-strict URL's
  • Using variables in URL's
  • Using middleware
  • Assign variables and use earlier assigned variables
  • Mark routes as non viewable
  • Set domain specific routes

Creating the first route

sFire\Routing\Router lets you listen to HTTP request based on a given URL. To create a new route, you will have to decide which HTTP method the route should listen to.

In the example below we want to listen to the HTTP GET method (by using the get method of the Router instance) on the url 'customer/details'. The second parameter of the get method is the unique identifier for this specific route. Every route should contain its own unique identifier, for you to determine. You can use these identifiers to generate a variable URL in the view for example.

Router :: get('customer/details', 'customer.details');

You must give a module, controller and action. To find all modules, you can look in the "modules/" directory. The name of the controller and actions are without the postfixes. So CustomerController.php will be "Customer" and detailsAction will be "details":

Router :: get('customer/details', 'customer.details') -> module('App') -> controller('Customer') -> action('details');

Handeling HTTP requests

If you want to listen to all HTTP methods or your application logic should handle it, you can use the any method.

Router :: any('url', 'identifier');

Below is a list of the existing HTTP methods:

Router :: get('url', 'identifier');
Router :: post('url', 'identifier');
Router :: delete('url', 'identifier');
Router :: put('url', 'identifier');
Router :: head('url', 'identifier');
Router :: connect('url', 'identifier');
Router :: options('url', 'identifier');
Router :: trace('url', 'identifier');
Router :: patch('url', 'identifier');

Grouping routes and prefix URL's

You can also group routes by calling the group method. This will allow you to set multiple options once for all the routes within the group. You can even group the groups. Pass a closure function to this method and use the injected route object to set new attributes within the new group.

Router :: module('App') -> group(function($route) {

    $route -> controller('Error') -> viewable(false) -> group(function($route) {

        //These routes will have the "App" as module, "error" as controller and "false" as viewable
        $route -> any('403', '403') -> action('403');
        $route -> any('404', '404') -> action('404');
    });

    //This route will have the "App" as module
    $route -> get('', 'home.index') -> controller('Home') -> action('index');
});
Prefix URL's

When grouping routes, you can prefix routes with a given URL using the prefix method. This method accepts a regular expression String that will be prepended to the url set with one of the HTTP methods.

Router :: module('App') -> prefix('customer/') -> group(function($route) {

    //The URL the route will listen to: "customer/overview"
    $route -> get('overview', 'customer.overview') -> controller('Customer') -> action('overview');

    //The URL the route will listen to: "customer/add"
    $route -> any('add', 'customer.add') -> controller('Customer') -> action('add');
});

You can also prepend the prefix by setting the second parameter to Boolean true:

Router :: module('App') -> prefix('dashboard/') -> group(function($route) {

    $route -> prefix('customer/', true) -> group(function($route) {

        //The URL the route will listen to: "dasboard/customer/overview"
        $route -> get('overview', 'customer.overview') -> controller('Customer') -> action('overview');
    });

    //Other routes
    [...]
});

Create error routes

When the current URL is not matched to a defined route url, a 404 HTTP status code will be triggerd. In other words, the page could not be found. You can create multiple 404 error routes by calling the error method. This method accepts a HTTP status code (Integer) as first parameter and a unique identifier for that route as second parameter.

Router :: module('App') -> controller('Error') -> group(function($route) {

    $route -> error(404, 'error.404-a') -> action('404a');
    $route -> error(404, 'error.404-b') -> action('404b');
    $route -> error(404, 'error.404-c') -> action('404c');
});

In this case you can redirect to a specific 404 route if a customer could not be found in the database for example. But if the URL does not match any route, sFire will look at the default 404 error route which is the first 404 error route you have set. In this case the route with "error.404-a" as identifier.

You can also set the third parameter to make another 404 error route the default:

$route -> error(404, 'error.404-a') -> action('404a');

//This will be the default 404 error route
$route -> error(404, 'error.404-b', true) -> action('404b'); 

Using strict and non-strict URL's

By default the Routes URL matching will test a given url in non strict-mode. The route url "customer/details" will match "customer/details?foo=bar". If you want to disable this, you can turn on strict-mode by calling the strict method.

Router :: get('customer/details', 'customer.details') -> strict(true);

Using variables in URL's

It's very easy to use variables in your URL's, for example a customer id. There are five predefined types you can use or you may create your own custom variable with regular expressions.

Types explained:

In the table below, you can see the predefined types.

Name Explanation
int Will match only integer numbers (1, 3, 10, 520, etc)
float Will match any number
boolean Will match only "true", "false", "0" or "1"
string Will match everything
alphanumeric Will only match all numbers and letters a to z and A to Z

Example:

//Will match the URL: "/customer/details/52"
Router :: get('customer/details/{int}', 'customer.details');
Optional variables:

To make a variable optional, you may use the "?" symbol after the type:

//Matches the URL: "/customer/details" and "/customer/details/52"
Router :: get('customer/details/{int?}', 'customer.details');
Create custom types:

You can create your own custom types to use witch will match a regular expression.

//Matches the URL: "/customer/details/5" but NOT "/customer/details/a"
Router :: get('customer/details/{id}', 'customer.details') -> where('id', '[0-9]+');

To set multiple wheres, you can give the custom types as an Array:

//Matches the URL: "/customer/details/5/bar"
Router :: get('customer/details/{id}/{foo}', 'customer.details') -> where(['id' => '[0-9]', 'foo' => 'bar']);
Grouping

When grouping routes, you can set the third parameter to Boolean false, to overwrite previous uses. By default, sFire will merge all the wheres into one where.

Router :: where('id', '[0-9]') -> group(function($route) {
    $route -> get('customer/add', 'customer.add') -> where('id', '[a-z]', false); 
}); 

Using middleware

Middleware provide a convenient mechanism for filtering HTTP requests entering your application. For example, middleware that verifies the user of your application is authenticated. If the user is not authenticated, the middleware can redirect the user to the login screen. However, if the user is authenticated, the middleware will allow the request to proceed further into the application.

sFire lets you assign middleware classes to routes:

//Assign the Authenticate middleware to a single route
Router :: get('customer', 'customer.index') -> middleware('Authenticate');

//Assign the Cors and Authenticate middleware to a single route
Router :: get('customer', 'customer.index') -> middleware('Cors', 'Authenticate');

Note: The order of the given middleware is the order of middleware execution.

Grouping

You may also group middleware:

Router :: middleware('Authenticate') -> group(function($route) {
    $route -> get('customer', 'customer.index'); //This route will inherrit the Authenticate middleware 
}); 

Assign variables and use earlier assigned variables

You can assign variables which can be retrieved in the Controller.

Assigning variables

To assign variables to routes, you can use the assign method:

routes.php
Router :: get('customer', 'customer.index') -> assign('foo', 'bar');
Controller
$this -> route() -> getParam('foo'); //Outputs "bar"
$this -> route() -> getParams(); //Outputs Array('foo' => 'bar')

You can also specify multiple variables by giving an Array:

Router :: get('customer', 'customer.index') -> assign(['foo' => 'bar', 'baz' => 'qux']);
Grouping

When grouping routes, you can set the third parameter to Boolean false, to overwrite previous assigns. By default, sFire will merge all the assigns into one assign.

Router :: assign('foo', 'bar') -> group(function($route) {
    $route -> get('customer', 'customer.index') -> assign('baz', 'qux', false); 
}); 

Use earlier assigned variables

Instead of defining duplicate variables for each different route, you can use the uses method to tell the route that it should use the variables of the given route identifier.

Router :: get('customer', 'customer.index') -> assign('foo', 'bar');

//Use the assigned variables of the "customer.index" route
Router :: get('customer/add', 'customer.add') -> uses('customer.index'); 

You can even set (or overwrite) more variables to combine multiple variables.

Router :: get('customer', 'customer.index') -> assign('foo', 'bar');
Router :: get('customer/add', 'customer.add') -> assign(['baz' => 'qux', 'fol' => 'peq']) -> uses('customer.index'); 

Router :: get('customer/add', 'customer.add') -> assign('quux', 'quuux') -> uses('customer.add'); 

//Assigned variables:
Array
(
    [quux] => quuux
    [baz] => qux
    [fol] => peq
    [foo] => bar
)
Grouping

When grouping routes, you can set the second parameter to Boolean false, to overwrite previous uses. By default, sFire will merge all the uses into one use.

Router :: get('customer', 'customer.index') -> assign('foo', 'bar');
Router :: get('customer/add', 'customer.add') -> assign(['baz' => 'qux', 'fol' => 'peq']); 

Router :: uses('customer.index') -> group(function($route) {

    //This route will only use the variables from the "customer.add" route
    $route -> get('customer/add', 'customer.add') -> uses('customer.add', false); 
}); 

Mark routes as non viewable

If you have routes that should not be accessible through the outside world (ie. browsers), you can mark routes as non viewable. This could be handy if you have a 403 Forbidden controller, but you don't want your users to navigate to this controller directly but do want to internal redirect (see the "Internal redirect" in Router.

You can set the viewable method to false:

Router :: any('403', '403') -> viewable(false);

Set domain specific routes

If your application is listening to multiple domains, you may define a single route to one or multiple domains. This way, you can have multiple domains with same URL's. You can create a new domain and map all the routes to that domain. The domain is a String that will be treated like a regular expression.

Set the domain name with the domain method:

//Single domain:
Router :: get('customer/details', 'customer.details') -> domain('sub1\.example\.com');

//As an Array:
Router :: get('customer/details', 'customer.details') -> domain(['sub1\.example\.com', 'sub2\.example\.com']);

you can also group routes for domains:

Router :: domain(['sub1\.example\.com', 'sub2\.example\.com']) -> group(function($route) {

    $route -> get('', 'home.index') -> controller('Home') -> action('index');
    $route -> get('customer', 'customer.index') -> controller('Customer') -> action('index');
});

These routes will listen to:

  • sub1.example.com/
  • sub1.example.com/customer
  • sub2.example.com/
  • sub2.example.com/customer

If your application is listening to multiple domains and/or modules, don't forget to set a default 404 error route:

//Create default 404 error route
Router :: error(404', 'error.404a', true) -> module('FallbackApp') -> controller('Error') -> action('404');

//Create a 404 error route for the "App" module and "example.com" domain
Router :: module('App') -> controller('Error') -> domain('example\.com') -> group(function($route) {
    $route -> error(404, 'error.404b') -> action('404');
});