Routing


Routing

Routing is the process or mechanism inside a framework that inspects incoming HTTP requests and matches them against defined routes to invoke the appropriate code. Meanwhile, a route is a specific path definition that pairs a URL pattern and HTTP method with a destination action. It defines where a request should go.

The URL pattern of a route can be something like /, /users/profile, or /posts/{id}. Meanwhile, the HTTP method can be GET, POST, PUT, or DELETE.

As with other PHP frameworks, in Zap, a route defines a controller action, closure, or class method. For instance, when a GET request comes in for /posts/5, send this request to PostsController@show() with ID=5.

In Zap, all routes are defined in the /routes/web.php file. Of course, you can add more routes file and require them in the /public/index.php. In the /routes/web.php, you can add new routes as follows:

Route::get('/login', 'AccountController@login')->name('account.login');

In this example, /login is the path, AccountController@login() means that the action or method is login() in the AccountController class. Meanwhile, account.login is the route name (this is arbitrary name, but make sure that it is unique).

Two or more routes can have the same path, but they should have their own action. For instance:

Route::post('/login', 'AccountController@loginHandler')->name('account.loginHandler');

If a single action method is used for different requests, the method will be messy and hard to maintain.

HTTP Request Methods

An HTTP request can be GET, POST, PUT, or DELETE. Native HTML form, however, only supports GET and POST. Meanwhile, AJAX (e.g., native XHR or via jQuery.ajax) supports all.

In Zap, when native HTML form is used for PUT or DELETE, the actual method must be set to POST, while adding a hidden field named _method with the value of PUT or DELETE.

<form action="{{ route('update.user') }}"; method="post">
 <div class="form-floating mb-3">
 <input type="text" name="user_fullname" id="user_fullname"/>
 <label for="user_fullname">Fullname</label>
 </div>
 <div class='form-floating mb-3'>
 <input type="email" name="email" id="email/>
 <label for="email">Email</label>
 </div>
 <div class="mb-3">
 <input type="hidden" name="userid" value="{{ $user['id'] }}"/>
 <input type="hidden" name="_method" value="PUT"/>
 <button type="submit" class="btn btn-dark">Update</button>
 </div>
</form>

In defining the route, you do not use post() but put(). For example:

Route::put('/user/update', 'UsersController@updateUser')->name('update.user');

Then, in the controller method, you process the request just like POST requests.

Named Routes

Routes should be named by using ->name('routename'), as you have seen above. Named routes are easier to call in the view, especially as the value of the href attribute. However, it is not required.

When a route name has been registered this way, you can use the helper route('routename') wherever you want in the app, except in using Litewire. In Litewire, you only use the path (e.g., /user/update) without the helper function.

<!-- Using helper -->
 <a href="{{ route('users.list') }}">List User</a>

 <!-- Using Litewire -->
 <div lw-get="/users/list" lw-trigger="load"></div>

Using route helper function in the Litewire will duplicate the full URL and trigger errors.

Middleware

A middleware intercepts an HTTP request and evaluates the request against conditions or rules defined in it. For instance, particular routes may be restricted to only those who are logged in, while those who are not will not have access to the routes.

All middleware classes must be located in the app/Middlewares directory and use proper namespace. Every middleware class must also have a handle() method. This is an example of a middleware:

<?php 
namespace Zap\App\Middlewares;
use Zap\Core\Http\Request;
use Zap\Core\Utils\SessionManager;
use Zap\Core\Utils\Container;
class GuestMiddleware {
 public function handle(Request $request, array $params, callable $next, string ...$roles) {
 $session = Container::getInstance()->make(SessionManager::class);
 if($session->has(config('app.session'))) {
 $loggedAccount = $session->get(config('app.session'));
 $route = $loggedAccount['account']['role'] . '.index';
 $this->go_to($route);
 }
 return $next($request, $params);
 }
 private function go_to(string $route) {
 header('location:'. route($route));
 exit;
 }
}

Then, each middleware must be registered in the /bootstrap/app.php.

<?php
//bootstrap/app.php
use Zap\App\Middlewares\AuthMiddleware;
use Zap\Core\Routing\Router;
use Zap\Core\Routing\RouteFacade;
use Zap\App\Middlewares\GuestMiddleware;
$router = new Router();
// Register all middleware aliases here
$router->aliasMiddleware('guest', GuestMiddleware::class);
$router->aliasMiddleware('auth', AuthMiddleware::class);
RouteFacade::setRouter($router);
return $router;

As you can see, you create an alias for each middleware and use the alias in defining the route.

Route::get('/login', 'AccountController@login')->name('account.login')->middleware('guest');
Route::get('/users', 'AccountController@users')->name('account.users')->middleware('auth', ['admin']);