Powered by Smartsupp

Action Pattern v Laravelu

Action Pattern v Laravelu

Většina projektů v Laravelu začíná idylicky. Pár kontrolerů, jednoduché modely a přehledné routy. Jakmile však aplikace začne růst, začnou se v kontrolerech hromadit desítky řádků byznys logiky. Validace, nahrávání souborů, odesílání notifikací a zápisy do databáze se míchají na jednom místě. Výsledkem je „Fat Controller“, který je noční můrou pro každého, kdo ho má později upravovat nebo testovat.

Právě zde přichází na scénu Action Pattern. Tento architektonický vzor vám umožní vyčlenit konkrétní byznys operace do samostatných, jednoúčelových tříd. Místo abyste měli jednu metodu kontroleru, která dělá pět věcí najednou, vytvoříte dedikovanou akci, která se soustředí na jedinou úlohu.

V tomto článku se podíváme na to, jak Action Pattern implementovat, proč je lepší než klasické Services a jak díky němu dosáhnout skutečně čisté architektury ve vašem Laravel projektu.

Problém: Past jménem Fat Controller

Představme si běžný scénář: registraci nového uživatele. V základním přístupu by váš kontroler mohl vypadat takto:

public function store(Request $request)
{
    $validated = $request->validate([
        'name' => 'required|string|max:255',
        'email' => 'required|email|unique:users',
        'password' => 'required|min:8',
    ]);

    $user = User::create([
        'name' => $validated['name'],
        'email' => $validated['email'],
        'password' => Hash::make($validated['password']),
    ]);

    $user->assignRole('customer');
    
    Mail::to($user)->send(new WelcomeEmail($user));
    Log::info("Uživatel {$user->id} se registroval.");

    return response()->json($user);
}

Na první pohled kód funguje. Problém nastane ve chvíli, kdy potřebujete uživatele vytvořit i přes API, CLI příkaz nebo v rámci importu z CSV. Budete logiku kopírovat? To je cesta do pekel.

Řešení: Co je to Action Pattern?

Action Pattern (nebo také vzor Command) spočívá v tom, že každou logickou operaci v aplikaci zapouzdříte do samostatné třídy. Tato třída má obvykle pouze jednu veřejnou metodu (např. execute nebo handle).

Proč používat akce místo Service Classes?

Zatímco UserService často končí jako obrovský soubor s 15 různými metodami (create, update, delete, block, notify...), Action je vždy jedna třída pro jednu věc.

Výhody Action Patternu:

  • Znovupoužitelnost: Akci zavoláte z kontroleru, Jobu i Artisan příkazu.

  • Testovatelnost: Testujete pouze jeden izolovaný kousek logiky.

  • Čitelnost: Ze struktury složek hned vidíte, co aplikace umí (např. CreateUserAction.php).

  • Single Responsibility: Třída dělá jen jednu věc a dělá ji dobře.

Praktická implementace: Vytvoření CreateUserAction

Vytvoříme si složku app/Actions a do ní vložíme naši první akci.

namespace App\Actions;

use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
use App\Mail\WelcomeEmail;

class CreateUserAction
{
    /**
     * Vykoná registraci uživatele a související procesy.
     */
    public function execute(array $data): User
    {
        $user = User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => Hash::make($data['password']),
        ]);

        $user->assignRole('customer');
        
        Mail::to($user)->send(new WelcomeEmail($user));

        return $user;
    }
}

Použití v kontroleru

Díky Service Containeru v Laravelu můžeme akci jednoduše injektovat do metody kontroleru.

namespace App\Http\Controllers;

use App\Http\Requests\RegisterRequest;
use App\Actions\CreateUserAction;

class RegisterController extends Controller
{
    public function __invoke(RegisterRequest $request, CreateUserAction $createUser)
    {
        $user = $createUser->execute($request->validated());

        return response()->json($user);
    }
}

Všimněte si, jak se kontroler vyčistil. Nyní se stará pouze o to, aby přijal požadavek a vrátil odpověď. Veškerá „špinavá“ práce probíhá uvnitř akce.

Pokročilé techniky: Invokovatelné akce

Mnoho vývojářů preferuje používat magickou metodu __invoke(). To vám umožní volat akci, jako by to byla funkce.

class CreateUserAction
{
    public function __invoke(array $data): User
    {
        // logika...
    }
}

// Volání v kontroleru pak vypadá takto:
$user = $createUser($request->validated());

Tento přístup je elegantní, ale v týmu se předem dohodněte na jednotném pojmenování (buď execute() nebo __invoke()), abyste udrželi konzistenci.

Kdy Action Pattern (ne)použít?

Action Pattern není stříbrná kulka. Pro velmi malé projekty nebo jednoduché CRUD operace (např. jen uložení jednoho pole do DB) může být zbytečným overengineeringem.

Kdy Action použít:

  1. Operace vyžaduje více kroků (DB zápis + e-mail + logování).

  2. Logiku potřebujete volat z více míst (Web + API).

  3. Chcete mít čisté a přehledné unit testy.

Shrnutí

Action Pattern v Laravelu představuje efektivní způsob, jak bojovat proti složitosti kódu. Tím, že byznys logiku vyčleníte z kontrolerů do samostatných tříd, získáte aplikaci, která je snadno rozšiřitelná, lépe se testuje a především – je radost v ní pracovat. Začněte postupně: identifikujte nejsložitější metodu ve svém kontroleru a zkuste ji přepsat do samostatné akce.

Chcete mít v týmu vývojáře, kteří píší takovýto kód? Spojte se s námi:
https://devboys.cz/kontakt

Co se stane po odeslání?

Jsme tu pro Vás

Vaši zprávu si přečtu přímo já nebo kolega z týmu. Do 24 hodin se vám ozveme zpět, abychom probrali detaily. Žádní obchodní zástupci, ale rovnou technická konzultace k věci, která vás posune dál.

Osobní přístup

Jednáte přímo s vývojáři, ne s account managery.

< 24 h reakční doba

Ozveme se rychle s jasnými dalšími kroky.

IČO 06109152
DIČ CZ9102040431 (Plátce DPH)
Společnost zapsaná v obch. rejstříku, vedeného MÚ Plzeň, spis. zn. 231/98.

Kontaktujte nás