dentro/yalr

Class base routing for laravel application.

v1.3.0 2024-03-18 15:17 UTC

This package is auto-updated.

Last update: 2024-11-18 16:56:58 UTC


README

Test Coding Standard codecov Total Downloads Laravel Octane Compatible

Define Laravel routes in different ways using Class Wrapper Route or Route Attribute

Previously known as jalameta/router.

TABLE OF CONTENT

Installation

Using composer :

composer require dentro/yalr

Requirements

Applying into your project

Run command in your project

php artisan yalr:install {--remove}

If you're deciding to remove the original laravel routes, you might add --remove option within the command. So the command will be

YALR will configure the routes for you, the Laravel default routes folder will be deleted. So backup your defined routes first.

Usage

Class Wrapper Route

Class wrapper route is our effort to make routing in laravel more expressive and separated. We usually make route that representative with namespace for easy to understand. For example, class App\Admin\TransactionRoute will represent route /app/admin/transaction.

Creating new route

To make a new route just run:

php artisan make:route DefaultRoute

After running command above, the route named DefaultRoute will appear in app/Http/Routes/DefaultRoute.php. After creating routes, it will not be loaded automatically, you must register the Route Class in the route configuration.

make:route options
  1. Inject Inject is useful options to auto adding the route class name within route configuration, so you don't need to add it manually. E.g:
php artisan make:route DefaultRoute --inject web

Command above will make the Default route within the web groups that defined in config/routes.php.

  1. Controller The controller option will generate the route and the controller used by the route. So you don't need to run 2 artisan command to create a new controller and route.
php artisan make:route DefaultRoute --controller HomeController
  1. Help Shows YALR command helps

Routes Configuration

Below is an example of YALR configurations.

return [
    'groups' => [
        'web' => [
            'middleware' => 'web',
            'prefix' => '',
        ],
        'api' => [
            'middleware' => 'api',
            'prefix' => 'api',
        ],
    ],

    'web' => [
        /** @inject web **/
	\App\Http\Routes\DefaultRoute::class,
    ],
    'api' => [
        /** @inject api **/
    ],
];

As you can see, groups index is group configuration, you can pass any laravel options there such as as, domain, middleware, prefix, etc. Afterward, the web and api are group index defined before in the groups index. It is an array of route class names.

Class Structure

After creating a route with the command, we will see the example of the generated file.

<?php

namespace App\Http\Routes;

use Dentro\Yalr\BaseRoute;

class DefaultRoute extends BaseRoute
{

    /**
     * Register routes handled by this class.
     *
     * @return void
     */
    public function register(): void
    {
        // Make an awesome route
    }
}

After creating a route with the command, we will see the example of the generated file. We can define routes within the register method. All you need is to call $this->router as a router instance. Then, we can invoke the laravel routing method such as post, put, etc. See Laravel Routing Docs.

Avoid using closure action, otherwise your application will encounter error when routes were cached.

<?php

namespace App\Http\Routes;

use Dentro\Yalr\BaseRoute;

class DefaultRoute extends BaseRoute
{

    protected string $prefix = 'wonderful';
    
    protected string $name = 'wonderful';
    
    /**
     * Register routes handled by this class.
     *
     * @return void
     */
    public function register(): void
    {
        $this->router->get('/', function () {
            return view('welcome');
        });
    }
}
Using Controller

From create route command, we know we can pass the controller namespace. The created controller will show up in the route class as a controller method.

<?php

namespace App\Http\Routes;

use Dentro\Yalr\BaseRoute;
use App\Http\Controllers\HomeController;

class DefaultRoute extends BaseRoute
{
    /**
     * Register routes handled by this class.
     *
     * @return void
     */
    public function register(): void
    {
        $this->router->get('/', [
            'uses' => $this->uses('index')
        ]);
    }
    
     /**
     * Controller used by this route.
     *
     * @return string
     */
    public function controller(): string 
    {
        return HomeController::class;
    }
}

The route above is equal with

Route::get('/', [
    'uses' => "App\Http\Controllers\HomeController@index"
]);

This package want to solve those duplicated namespace and class name several times as we define the routes. Or if you don't want to use the controller in the route class, you can pass the second parameter of $this->uses() method with the controller class name to be used, E.g : $this->uses('login', LoginController::class).

Route Prefix

Override the route prefix defined in the class property. Default prefix is '/';

protected string $prefix = '/home';

$this->router->get($this->prefix(), [
    'uses' => $this->uses('index')
]);

The route above is equal with

Route::get('/home', [
    'uses' => "App\Http\Controllers\HomeController@index"
]);
Route Name

You need to define the route name property within the route class

protected string $name = 'home';

Later we can use $this->name() method for adding separation with dot (.) between the route group name, and the single route name

$this->router->get('/', [
    'as' => $this->name('landing'),
    'uses' => $this->uses('index')
]);

It equal with

Route::get('/', [
    'as' => 'home.landing',
    'uses' => "App\Http\Controllers\HomeController@index",
]);

Preloads

Preloads always run even though routes been cached. It might be the good place to put route model binding and rate limiter there.
Example :

// config/routes.php

'preloads' => [
    App\Http\RouteModelBinding::class,
    App\Http\RouteRateLimiter::class,
],
namespace App\Http;

use Dentro\Yalr\Contracts\Bindable;

class RouteModelBinding implements Bindable 
{
    public function __construct(protected Router $router)
    {
    }

    public function bind(): void
    {
        $this->router->bind('fleet_hash', fn ($value) => Fleet::byHashOrFail($value));
        $this->router->bind('office_slug', fn ($value) => Office::query()->where('slug', $value)->firstOrFail());
    }
}
namespace App\Http;

use Dentro\Yalr\Contracts\Bindable;

class RouteRateLimiter implements Bindable 
{
    public function __construct(protected Router $router)
    {
    }

    public function bind(): void
    {
        RateLimiter::for('api', function (Request $request) {
            return Limit::perMinute(360)->by($request->user()?->email.$request->ip());
        });
    }
}

Route Attribute

PHP 8 comes up with a nice feature called Attribute see this link for the detail. So we added those feature to this package for us to create something like the example below.

#[Middleware(['auth:sanctum', 'verified'])]
class DashboardController extends Controller
{
    #[Get('dashboard', name: 'dashboard')]
    public function index(): Response
    {
        return Inertia::render('Dashboard');
    }
}

Available Class Target

Dentro\Yalr\Attributes\Domain(string $domain);
Dentro\Yalr\Attributes\Prefix($prefix);
Dentro\Yalr\Attributes\Name(string $name, bool $dotPrefix = false, bool $dotSuffix = false);
Dentro\Yalr\Attributes\Middleware(string | array $middleware);

Available Method Target

Dentro\Yalr\Attributes\Get(string $uri, ?string $name = null, array | string $middleware = [], array | string $withoutMiddleware = []);
Dentro\Yalr\Attributes\Post(string $uri, ?string $name = null, array | string $middleware = [], array | string $withoutMiddleware = []);
Dentro\Yalr\Attributes\Put(string $uri, ?string $name = null, array | string $middleware = [], array | string $withoutMiddleware = []);
Dentro\Yalr\Attributes\Patch(string $uri, ?string $name = null, array | string $middleware = [], array | string $withoutMiddleware = []);
Dentro\Yalr\Attributes\Delete(string $uri, ?string $name = null, array | string $middleware = [], array | string $withoutMiddleware = []);
Dentro\Yalr\Attributes\Options(string $uri, ?string $name = null, array | string $middleware = [], array | string $withoutMiddleware = []);
Dentro\Yalr\Attributes\Delete(string $uri, ?string $name = null, array | string $middleware = [], array | string $withoutMiddleware = []);

Added To Configuration Route

just put class to your route configuration and yalr will figure it out what to do with your controller.

    'web' => [
        /** @inject web **/
	\App\Http\Routes\DefaultRoute::class,
        \App\Http\Controller\DashboardController::class,
    ],