PHPackages                             andydefer/laravel-actions - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. andydefer/laravel-actions

ActiveLibrary[Framework](/categories/framework)

andydefer/laravel-actions
=========================

Action-oriented architecture for Laravel applications

v2.4.6(4w ago)0261MITPHPPHP &gt;=8.1

Since May 25Pushed 1mo agoCompare

[ Source](https://github.com/andydefer/laravel-actions)[ Packagist](https://packagist.org/packages/andydefer/laravel-actions)[ RSS](/packages/andydefer-laravel-actions/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependencies (16)Versions (18)Used By (1)

Laravel Actions
===============

[](#laravel-actions)

[![Latest Version on Packagist](https://camo.githubusercontent.com/32e05a758f3e81e6fb7d972d642730df6b6d708f3a7258159f0c72e1334b6ddd/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f616e647964656665722f6c61726176656c2d616374696f6e732e737667)](https://packagist.org/packages/andydefer/laravel-actions)[![PHP Version Require](https://camo.githubusercontent.com/83bd61eea80d0f356fd340c9ee2c23e8728077c6eb1926a3c96c937f0001575a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f616e647964656665722f6c61726176656c2d616374696f6e732e737667)](https://packagist.org/packages/andydefer/laravel-actions)[![Laravel Version](https://camo.githubusercontent.com/9f235d3913901c94bd05e1d65afc2e43d1cc4627057f5d36e9c10bbafaa40bb1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d3130253246313125324631322532463133253246313425324631352d6666326432302e737667)](https://laravel.com)[![License](https://camo.githubusercontent.com/2ab379ea14f0921de44007a04b48d64dc561f9ba9f15b6ecb5b799748c12e58f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f616e647964656665722f6c61726176656c2d616374696f6e732e737667)](https://packagist.org/packages/andydefer/laravel-actions)

Table des matières
------------------

[](#table-des-matières)

- [Introduction](#introduction)
- [Philosophie](#philosophie)
- [Installation](#installation)
- [Concepts clés](#concepts-cl%C3%A9s)
- [Guide de démarrage](#guide-de-d%C3%A9marrage)
- [Documentation détaillée](#documentation-d%C3%A9taill%C3%A9e)
- [Tests](#tests)
- [Compatibilité](#compatibilit%C3%A9)
- [License](#license)

---

Introduction
------------

[](#introduction)

**Laravel Actions** est un package qui implémente le pattern **ADR (Action-Domain-Responder)** pour Laravel. Il transforme vos contrôleurs en classes d'action simples, testables et maintenables.

Chaque route HTTP est associée à une **Action** (logique métier) et une **Request** (validation et transformation des données).

```
// Au lieu d'un contrôleur avec 5 méthodes
class UserController extends Controller
{
    public function index() { ... }
    public function show($id) { ... }
    public function store(Request $request) { ... }
    // ...
}

// Vous avez 5 classes d'action dédiées
final class ListUsersAction extends AbstractAction { ... }
final class ShowUserAction extends AbstractAction { ... }
final class CreateUserAction extends AbstractAction { ... }
```

---

Philosophie
-----------

[](#philosophie)

PrincipeApplication dans le package**Single Responsibility**Une Action = une route HTTP**Type Safety**Records typés entre Request et Action**Testabilité**Actions sans helpers globaux, seulement des dépendances injectées**Immutabilité**Records et Data DTOs sont readonly**Template Method**Cycle de vie `before()` → `handle()` → `after()`---

Installation
------------

[](#installation)

```
composer require andydefer/laravel-actions
```

Le package s'enregistre automatiquement via Laravel's auto-discovery.

---

Concepts clés
-------------

[](#concepts-clés)

### 1. AbstractAction

[](#1-abstractaction)

Classe de base pour toutes vos actions. Implémente le pattern **Template Method**.

```
final class CreateUserAction extends AbstractAction
{
    public function __construct(
        private readonly UserRepositoryInterface $users
    ) {}

    protected function handle(AbstractRecord $request): ResponseFactory
    {
        $user = $this->users->create($request->toArray());
        return ResponseFactory::json(UserData::from($user), 201);
    }
}
```

**Cycle de vie :**

```
run(Record) → before() → handle() → after() → ResponseFactory

```

### 2. AbstractRequest

[](#2-abstractrequest)

Classe de base pour vos requêtes. Étend `FormRequest` de Laravel.

```
final class CreateUserRequest extends AbstractRequest
{
    public function rules(): array
    {
        return [
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'email', 'unique:users'],
        ];
    }

    public function getRecord(): AbstractRecord
    {
        return CreateUserRecord::from([
            'name' => $this->input('name'),
            'email' => $this->input('email'),
        ]);
    }
}
```

### 3. AbstractRecord

[](#3-abstractrecord)

DTO typé pour transporter les données entre la Request et l'Action.

```
final class CreateUserRecord extends AbstractRecord
{
    public function __construct(
        public readonly string $name,
        public readonly string $email,
    ) {}
}
```

### 4. AbstractData

[](#4-abstractdata)

DTO immutable pour les réponses HTTP (converti automatiquement en camelCase).

```
final class UserData extends AbstractData
{
    public function __construct(
        public readonly string $id,
        public readonly string $name,
        public readonly string $email,
    ) {}
}
```

### 5. ResponseFactory

[](#5-responsefactory)

Factory pour construire des réponses HTTP de manière déclarative.

```
return ResponseFactory::json($userData);           // JSON API
return ResponseFactory::inertia('Dashboard/Index'); // Inertia SPA
return ResponseFactory::redirectRoute('home');     // Redirection
return ResponseFactory::noContent();               // 204 No Content
return ResponseFactory::fileDownload($path);       // Téléchargement
```

### 6. Fonction helper `action_route()`

[](#6-fonction-helper-action_route)

Fonction utilitaire qui retourne une closure pour associer une Request et une Action à une route. Cette approche préserve toute l'API fluide du `RouteRegistrar`.

```
use function action_route;

Route::get('/api/users', action_route(ListUsersRequest::class, ListUsersAction::class))
    ->name('users.index')
    ->middleware('auth');

Route::post('/api/users', action_route(CreateUserRequest::class, CreateUserAction::class))
    ->name('users.store')
    ->middleware('throttle:10,1');

Route::get('/api/users/{id}', action_route(ShowUserRequest::class, ShowUserAction::class))
    ->name('users.show')
    ->where('id', '[0-9]+');
```

### 7. Fonction helper `action_factory()`

[](#7-fonction-helper-action_factory)

Fonction utilitaire pour les routes simples qui n'ont pas besoin d'une Action dédiée. Parfaite pour les health checks, redirections simples ou vues statiques.

**Règle d'utilisation :** Une ligne = `action_factory()` | Deux lignes ou plus = Créer une Action complète

```
use function action_factory;
use App\Data\HealthData;

// Health check avec DTO
Route::get('/health', action_factory(
    ResponseFactory::json(HealthData::from(['status' => 'ok', 'timestamp' => now()->toIso8601String()]), 200)
))->name('api.health')->middleware('api');

// Redirection simple
Route::get('/redirect', action_factory(ResponseFactory::redirectRoute('home')));

// Vue statique
Route::get('/home', action_factory(ResponseFactory::view('welcome')));

// Fichier inline
Route::get('/resume', action_factory(ResponseFactory::fileInline(storage_path('resume.pdf'))));

// Téléchargement
Route::get('/export', action_factory(ResponseFactory::fileDownload(storage_path('export.csv'), 'data.csv')));

// 204 No Content
Route::delete('/resource/{id}', action_factory(ResponseFactory::noContent()));

// Texte brut
Route::get('/robots.txt', action_factory(ResponseFactory::text("User-agent: *\nDisallow: /private/")));
```

**Important :** `ResponseFactory::json()` nécessite un objet `AbstractData`. Les tableaux bruts ne sont pas acceptés.

```
// ❌ Erreur - Tableau brut non accepté
Route::get('/health', action_factory(ResponseFactory::json(['status' => 'ok'], 200)));

// ✅ Correct - Utilisation d'un DTO
Route::get('/health', action_factory(ResponseFactory::json(HealthData::from(['status' => 'ok']), 200)));
```

---

Guide de démarrage
------------------

[](#guide-de-démarrage)

### Étape 1 : Créer un Record

[](#étape-1--créer-un-record)

```
// app/Records/ShowUserRecord.php
