Routing & Middleware

Routing & Middleware

Useful for defining fixed APIs and endpoints.

While routing is handled automatically for the backend controllers and CMS pages define their own URL routes in their page configuration. Plugins can also supply a file named routes.php that contain custom routing logic, as defined in the Laravel router service (opens new window).

├── plugins | └── acme ← Author Name | └── blog ← Plugin Name | ├── controllers | ├── models | ├── Plugin.php | └── routes.php ← Routes File

Using this approach, routes are defined in PHP using the Route facade. Below is an example route that becomes available via https://yoursite.tld/api_acme_blog/cleanup_posts using a GET request.

Route::get('api_acme_blog/cleanup_posts', function() {
    return Posts::cleanUp();
});

You may generate URLs to your routes using the Url facade.

$url = Url::to('api_acme_blog/cleanup_posts');

# Basic Routing

To define routes, the PHP method will assocaite to the HTTP method, which supports get, post, patch, put, options and delete. The most basic routes simply accept a URI and a Closure.

Route::get('/', function () {
    return 'Hello World';
});

Route::post('foo/bar', function () {
    return 'Hello World';
});

Route::put('foo/bar', function () {
    //
});

Route::delete('foo/bar', function () {
    //
});

# Registering Multiple Methods

Sometimes you may need to register a route that responds to multiple HTTP methods. You may do so using the match method.

Route::match(['get', 'post'], '/', function () {
    return 'Hello World';
});

You may even register a route that responds to all HTTP methods using the any method.

Route::any('foo', function () {
    return 'Hello World';
});

# Routing to a Class

For larger applications it is preferable to organize routes inside classes instead of a closure. The best place to put these classes is in the handlers directory. The route can be referenced as an array that takes the class name and method name. In this example the /install route is mapped to the Installer class and install method.

Route::any('/install', [Installer::class, 'index']);

Next, define the class and the route inside. In this example the file is located in app/handlers/Installer.php.

namespace App\Handlers;

class Installer extends \Illuminate\Routing\Controller
{
    /**
     * Route: /install
     */
    public function install()
    {
        return 'Welcome!';
    }
}

# Route Parameters

To capture segments of the URI within your route, you may do so by defining route parameters. Ror example, capturing a user's ID from the URL.

Route::get('user/{id}', function ($id) {
    return 'User '.$id;
});

You may define as many route parameters as required by your route.

Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
    //
});

Route parameters are always encased within singular curly brackets. The parameters will be passed into your route's Closure when the route is executed.

Route parameters cannot contain the - character, use an underscore (_) instead.

# Optional Parameters

Occasionally you may need to specify a route parameter, but make the presence of that route parameter optional. You may do so by placing a ? mark after the parameter name:

Route::get('user/{name?}', function ($name = null) {
    return $name;
});

Route::get('user/{name?}', function ($name = 'John') {
    return $name;
});

# Regular Expression Constraints

You may constrain the format of your route parameters using the where method on a route instance. The where method accepts the name of the parameter and a regular expression defining how the parameter should be constrained.

Route::get('user/{name}', function ($name) {
    //
})->where('name', '[A-Za-z]+');

Route::get('user/{id}', function ($id) {
    //
})->where('id', '[0-9]+');

Route::get('user/{id}/{name}', function ($id, $name) {
    //
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);

# Named Routes

Named routes allow you to conveniently generate URLs or redirects for a specific route. You may specify a name for a route using the as array key when defining the route:

Route::get('user/profile', ['as' => 'profile', function () {
    //
}]);

# Route Groups & Named Routes

If you are using route groups (below), you may specify an as keyword in the route group attribute array, allowing you to set a common route name prefix for all routes within the group:

Route::group(['as' => 'admin::'], function () {
    Route::get('dashboard', ['as' => 'dashboard', function () {
        // Route named "admin::dashboard"
    }]);
});

# Generating URLs to Named Routes

Once you have assigned a name to a given route, you may use the route's name when generating URLs or redirects via the Url::route method:

$url = Url::route('profile');

$redirect = Response::redirect()->route('profile');

If the route defines parameters, you may pass the parameters as the second argument to the route method. The given parameters will automatically be inserted into the URL:

Route::get('user/{id}/profile', ['as' => 'profile', function ($id) {
    //
}]);

$url = Url::route('profile', ['id' => 1]);

# Route Groups

Route groups allow you to share route attributes across a large number of routes without needing to define those attributes on each individual route. Shared attributes are specified in an array format as the first parameter to the Route::group method.

# Sub-domain Routing

Route groups may also be used to route wildcard sub-domains. Sub-domains may be assigned route parameters just like route URIs, allowing you to capture a portion of the sub-domain for usage in your route or controller. The sub-domain may be specified using the domain key on the group attribute array:

Route::group(['domain' => '{account}.example.com'], function () {
    Route::get('user/{id}', function ($account, $id) {
        //
    });
});

# Route Prefixes

The prefix group array attribute may be used to prefix each route in the group with a given URI. For example, you may want to prefix all route URIs within the group with admin:

Route::group(['prefix' => 'admin'], function () {
    Route::get('users', function () {
        // Matches The "/admin/users" URL
    });
});

You may also use the prefix parameter to specify common parameters for your grouped routes:

Route::group(['prefix' => 'accounts/{account_id}'], function () {
    Route::get('detail', function ($account_id) {
        // Matches The accounts/{account_id}/detail URL
    });
});

# Route Middleware

Registering middleware inside your plugin's boot() method will register it globally for each request. If you want to register middleware to one route at a time you should do it like this:

Route::get('info', [\App\News::class, 'info'])->middleware(\Path\To\Your\Middleware::class);

For route groups it could be done like this:

Route::group(['middleware' => \Path\To\Your\Middleware::class], function() {
    Route::get('info', [\App\News::class, 'info']);
});

And finally, if you want to assign a group of middleware to just one route you can it like this

Route::middleware([\Path\To\Your\Middleware::class])->group(function() {
    Route::get('info', [\App\News::class, 'info']);
});

You can of course add more than one middleware in a group, just one is used in the above examples for convenience.

# Global Middleware

To register a global middleware, you can extend the Cms\Classes\CmsController or Backend\Classes\BackendController controller class by using the following method.

public function boot()
{
    \Cms\Classes\CmsController::extend(function($controller) {
        $controller->middleware(\App\Middleware::class);
    });
}

Alternatively, you can push it directly into the Kernel via the boot() registration method.

public function boot()
{
    // Add a new middleware to beginning of the stack.
    $this->app[\Illuminate\Contracts\Http\Kernel::class]
        ->prependMiddleware(\App\Middleware::class);

    // Add a new middleware to end of the stack.
    $this->app[\Illuminate\Contracts\Http\Kernel::class]
        ->pushMiddleware(\App\Middleware::class);
}

# Throwing 404 Errors

There are two ways to manually trigger a 404 error from a route. First, you may use the abort helper. The abort helper simply throws a Symfony\Component\HttpFoundation\Exception\HttpException with the specified status code.

App::abort(404);

You may also manually throw an instance of October\Rain\Exception\NotFoundException. More information on handling 404 exceptions and using custom responses for these errors may be found in the errors & logging section of the documentation.

# See Also