Skip to content

Attributes Usage

Laraventus adds support for PHP attributes to define middleware directly above your controller methods, making your code cleaner and more expressive.

This feature is enabled by default. To disable it, change the configuration file laraventus.php:

<?php
return [
"controller" => [
"attributes" => false
],
];

This middleware automatically scans for attributes that extend Aventus\Laraventus\Attributes\Middleware and executes them when attached to controller methods.

Let’s create a simple example that denies access to a route.

<?php
namespace App\Http\Middlewares;
use Attribute;
use Aventus\Laraventus\Attributes\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Http\JsonResponse;
#[Attribute(Attribute::TARGET_METHOD)]
class Deny extends Middleware
{
public function __construct() {
parent::__construct(Deny::class);
}
public function handle(Request $request, Closure $next): Response
{
return new JsonResponse([], 403);
}
}
  • The #[Attribute] decorator makes the class usable as a PHP attribute.
  • It extends Aventus\Laraventus\Attributes\Middleware, allowing Laraventus to detect and execute it automatically.
  • The handle method defines what happens when the middleware is triggered. Here, it simply returns a 403 Forbidden JSON response.

Now you can use it directly above your controller method:

<?php
namespace App\Http\Controllers\HelloWorld;
use App\Http\Middlewares\Deny;
class Controller
{
#[Deny]
public function request(Request $request): Error|Response
{
return new Response("Hello " . $request->name);
}
}

When the route is called, the Deny middleware runs before the controller logic and stops execution, returning a 403 response.

Result

{
"result": [],
"errors": [],
"$type": "Aventus.Laraventus.Helpers.LaravelResult"
}

With an HTTP status: 403 Forbidden

In more complex scenarios, you might want to automatically wrap your controller logic in a database transaction. Committing only when everything succeeds, and rolling back if any error occurs.

With Laraventus, you can achieve this cleanly using an Attribute-based middleware.

<?php
namespace App\Http\Middlewares;
use Attribute;
use Aventus\Laraventus\Attributes\Middleware;
use Aventus\Laraventus\Helpers\AventusError;
use Aventus\Laraventus\Helpers\LaravelResult;
use Closure;
use Exception;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Response as HttpResponse;
#[Attribute(Attribute::TARGET_METHOD)]
class Transaction extends Middleware
{
public function __construct() {
parent::__construct(Transaction::class);
}
public function handle(Request $request, Closure $next): Response
{
DB::beginTransaction();
try {
$response = $next($request);
if ($response instanceof Response) {
if ($response instanceof JsonResponse || $response instanceof HttpResponse) {
$data = $response->getOriginalContent();
if ($data instanceof LaravelResult && count($data->errors) > 0) {
DB::rollBack();
} else if ($data instanceof AventusError) {
DB::rollBack();
} else {
DB::commit();
}
} else {
DB::commit();
}
}
return $response;
} catch (Exception $e) {
DB::rollBack();
throw $e;
}
}
}
<?php
namespace App\Http\Controllers\User;
use App\Http\Middlewares\Transaction;
class Controller
{
#[Transaction]
public function changeName(Request $request): Error|Response
{
// All database operations inside this method
// will be executed within a transaction.
// Example:
// $user = User::find($request->id);
// $user->name = $request->newName;
// $user->save();
return new Response("User name changed successfully");
}
}

When the controller is executed:

  • A database transaction begins before your code runs.
  • If your controller (or any middleware) throws an exception or returns an AventusError / LaravelResult containing errors, the transaction rolls back.
  • If everything succeeds, the transaction commits automatically.

By using attribute-based middlewares, Laraventus lets you:

  • Define custom logic (e.g., access control, logging, rate limiting) directly above your route functions.
  • Keep your controller code clean and self-contained.
  • Maintain strong typing and structure consistent with Laravel’s conventions but with the added simplicity of attribute-driven behavior