Naar de inhoud
Recognized by Laravel Match je project Contact

Gebruik Action-classes voor businesslogica

Voor het laatst bijgewerkt op:

Beschrijving

Kapsel herbruikbare businessoperaties in met één doel gerichte action-classes met expliciete afhankelijkheden.

Aanbevolen situatie

Gebruik dit wanneer businesslogica omvangrijk is, hergebruikt wordt over meerdere ingangen, of afhankelijk is van externe services.

Menselijke begeleiding

Action-classes zijn aanroepbare classes met één doel die één afzonderlijke businessoperatie inkapselen. In combinatie met constructor dependency injection en het programmeren tegen interfaces op systeemgrenzen houden ze controllers dun, businesslogica testbaar en externe afhankelijkheden uitwisselbaar.

Waarom

  • Single responsibility: Elke action-class doet één ding goed, waardoor businesslogica eenvoudig te vinden, te testen en aan te passen is
  • Herbruikbaarheid: Dezelfde action kan worden aangeroepen vanuit controllers, commands, jobs en andere actions
  • Testbaarheid: Constructor injection maakt afhankelijkheden expliciet en eenvoudig te mocken
  • Uitwisselbaarheid: Programmeren tegen interfaces op systeemgrenzen (payment gateways, notificatiekanalen, externe API's) maakt het mogelijk implementaties te vervangen zonder de businesslogica te wijzigen

Geschikt voor

  • Businessoperaties die vanuit meerdere plekken worden aangeroepen (controllers, commands, jobs)
  • Operaties met externe afhankelijkheden die in tests mockbaar moeten zijn
  • Complexe operaties die controllers of jobs te groot zouden maken
  • Applicaties met meerdere integratiepunten (payment providers, verzendservices, enz.)

Minder geschikt voor

  • Eenvoudige CRUD-operaties die maar op één plek worden gebruikt
  • Operaties waarbij één Eloquent-aanroep volstaat
  • Prototyping of wegwerpcode waar de overhead niet gerechtvaardigd is

Voorbeelden

Action-class met één doel

class CreateOrderAction
{
    public function __construct(private InventoryService $inventory) {}

    public function execute(array $data): Order
    {
        $order = Order::create($data);
        $this->inventory->reserve($order);

        return $order;
    }
}

Gebruik dependency injection

Gebruik altijd constructor injection. Vermijd app() of resolve() binnen classes:

// Slecht: service locator-patroon
class OrderController extends Controller
{
    public function store(StoreOrderRequest $request)
    {
        $service = app(OrderService::class);

        return $service->create($request->validated());
    }
}

// Goed: constructor injection
class OrderController extends Controller
{
    public function __construct(private OrderService $service) {}

    public function store(StoreOrderRequest $request)
    {
        return $this->service->create($request->validated());
    }
}

Programmeer tegen interfaces op systeemgrenzen

Steun op contracts voor externe integraties om testbaarheid en uitwisselbaarheid mogelijk te maken:

// Slecht: concrete afhankelijkheid
class OrderService
{
    public function __construct(private StripeGateway $gateway) {}
}

// Goed: interface-afhankelijkheid
interface PaymentGateway
{
    public function charge(int $amount, string $customerId): PaymentResult;
}

class OrderService
{
    public function __construct(private PaymentGateway $gateway) {}
}

Bind in een service provider:

$this->app->bind(PaymentGateway::class, StripeGateway::class);

Meer informatie

Boost guideline

---
title: Use Action Classes for Business Logic
description: Encapsulate reusable business operations in single-purpose action classes with explicit dependencies.
recommended_situation: Use when business logic is substantial, reused across entry points, or depends on external services.
---

- Extract substantial business operations into focused action classes instead of embedding them in controllers, commands, or jobs.
- Give each action one clear responsibility and inject its collaborators through the constructor.
- Reuse actions across entry points when the same operation is triggered from HTTP, CLI, queues, or events.
- Depend on interfaces at external system boundaries so business logic remains testable and implementations stay swappable.
Skill

Laravel Boost Skill

Gebruik deze skill om de richtlijn rechtstreeks toe te passen met een AI-assistent.

Use this skill when a Laravel task touches this best practice. It is self-contained so it can be installed independently by Laravel Boost or another agent-skill system.

## Core Guidance



## Why It Matters

- Apply the best practice consistently and keep the implementation focused.

## Apply When

- Laravel work that directly overlaps with this practice.

## Be Careful When

- Tasks outside this practice; use a more specific skill instead.

## Canonical Source

- Full best practice: https://github.com/Dutch-Laravel-Foundation/best-practices/blob/main/project-structure-and-code-architecture/use-action-classes-for-business-logic/BEST_PRACTICE.md
- Dutch translation: https://github.com/Dutch-Laravel-Foundation/best-practices/blob/main/project-structure-and-code-architecture/use-action-classes-for-business-logic/translations/nl.md

## Workflow

1. Inspect the user's Laravel code before recommending changes.
2. Identify the narrow rule from this best practice that applies to the task.
3. Prefer Laravel's built-in conventions and documented APIs over custom abstractions.
4. Keep examples focused on this practice; reference other skills or practices when the task crosses boundaries.
5. Verify code changes with the project's available tests, linters, static analysis, or framework checks.

## Review Checklist

- The recommendation is Laravel-specific and grounded in this practice.
- Code examples use realistic Laravel file names, class names, and method names.
- The advice avoids mixing unrelated architecture, deployment, security, or testing topics.
- Related practices are mentioned when useful, but not re-explained in full.
- Dutch output, when requested, keeps framework and API names intact.