Loading...

This is taking longer than expected.

Coding standards

Application Classes

These are the standards the analyzer applies. Every rule states what it checks and why it exists.

All standards

Where Code Belongs

Before writing a class, decide where the code belongs by walking this order and stopping at the first match:

  1. Package — the code belongs to a domain being isolated (e.g. billing), so it lives in the package along with everything that domain needs.
  2. Model — the code is about one record, or about the records stored for it. $user->markLoggedIn(), User::emailExists($email), $plan->can_be_deleted.
  3. Service — the code talks to an external system: a payment provider, an API, an SMS gateway, a geolocation lookup. See the Services standard.
  4. Helper — the code is a pure function that only transforms its arguments, and more than one place needs it. See "Shared Utilities Belong in Helpers" in the PHP standard.
  5. Livewire component, middleware, observer, or job — the code is the entry point that receives the request or reacts to an event, and the work is small enough to read there.
  6. Action — a single synchronous operation that must return its result to the caller. One class per operation, in app/Actions/ for the host application or src/Actions/ inside a package, with a handle() method that returns the result; it runs in-process and returns a value, unlike a job, which may be queued.
  7. Application class in app/Classes/ — none of the above fit, and the code has a purpose of its own worth naming.

An application class is for logic that the application owns but no single record does, and that reaches no external system: a value object, a domain calculation spanning several models, an engine, or a flow driven from a middleware where there is no Livewire component to hold it.

// Correct — the referral program owns capturing a code and registering the referral
App\Classes\Referrals

// Correct — plan limits are a domain calculation that no single model owns
App\Classes\PlanLimits

// Incorrect — this is a question about stored users, so it belongs on the model
App\Classes\UserEmailChecker

Package Isolation

A package isolates all the code related to one domain. The package may use host (app/) classes.
The host must not contain the package's logic: it only bridges through traits and helpers that delegate and return null/empty when the package is disabled or absent.
The host must not reference the package namespace directly outside the guard helpers.

Single Use Is Not a Reason to Move Logic to the Model

Moving a method to a model is justified when the model is the right owner, not when the current class feels large. A method with a single caller may stay in the application class that owns the flow.
Conversely, a method used from several places is not automatically model material either: apply the order above and ask what the code is about, not how often it runs.
When the record is the owner, the model names the action and the class keeps the mechanics: $user->recordPaidSubscriptionReward(...) exposes the vocabulary on the model and delegates to the application class that owns the referral flow.

Actions

An action is a single synchronous operation that must return its result to the caller — a true/false, a record, a DTO. It looks like a job, but it runs in-process and returns a value; make it a job only when the work may be queued.
One class per operation, in app/Actions/ for the host application or src/Actions/ inside a package, with a handle() method that returns the result:

// Correct — one operation, returns the outcome to the caller
$ok = app(RecordSubscriptionReward::class)->handle($user, $amount, $currency, $invoiceId);

// Incorrect — a job used only to get a return value
dispatch(new RecordSubscriptionReward($user, $amount));

An application class is different: it keeps the logic and state of a domain — properties and several methods that serve it, like App\Classes\Referrals. An action performs one thing; a class owns a flow.

Weblabor Logo Developed by Weblabor