Where Code Belongs
Before writing a class, decide where the code belongs by walking this order and stopping at the first match:
- Package — the code belongs to a domain being isolated (e.g. billing), so it lives in the package along with everything that domain needs.
- Model — the code is about one record, or about the records stored for it.
$user->markLoggedIn(),User::emailExists($email),$plan->can_be_deleted. - Service — the code talks to an external system: a payment provider, an API, an SMS gateway, a geolocation lookup. See the Services standard.
- 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.
- 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.
- 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.
- 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