Coding Standards
The canonical rules for all Bagisto code, in one place, so a change to a
DataGrid, a payment class or a theme is held to the same bar as a change to a
package.
Pint decides the mechanical questions. Run vendor/bin/pint and trust it for
spacing, import order, trailing commas and the rest. What follows is what Pint
cannot see — and what a reviewer will otherwise send back.
Reference files
| File |
Load when |
| code-style.md |
Writing any PHP — multi-clause conditions, class member order |
| comments.md |
Any comment or docblock, in any language |
| laravel.md |
Framework idiom — events, migrations, config, helpers, validation, queues |
| data-access.md |
Reading or writing the database — the repository rule and its one exception |
| security.md |
Output, input, uploads, SQL, secrets, payments |
| security-authorization.md |
Routes, permissions, guards, one user's access to another's data |
| blade.md |
Any .blade.php — namespaces, : versus ::, components, page skeleton |
| blade-formatting.md |
Indentation, attribute layout, @props alignment, recipes |
| localization.md |
Any user-facing string, or a Resources/lang/ change |
The PHP rules apply inside an @php block too, which Pint cannot reach.
The rules in one screen
- Every method and property carries a docblock, whatever its visibility. The
description is a capitalised sentence ending in a full stop, and it is at most
two lines. Type information belongs in the signature; add
@param/@return
only for what a native type cannot express.
- Class members run constants → properties → constructor → public →
protected → private, each visibility one contiguous block. A helper called
by a public method still lives in the protected block at the bottom.
- A condition with more than one clause goes multiline, the boolean operator
leading each line. Single-clause conditions stay inline. The rule keys off the
number of clauses, not the line length.
- No comments inside method bodies, object literals or markup — not even a
one-line "why". A non-obvious reason belongs in the method's docblock or the
commit message. If a line needs prose to be understood, extract a named
method instead. See comments.md.
- No docblock above the class, ever — 98.7% of core classes have none. The
docblock belongs on the method, property or constant, never on the class,
interface, trait or enum.
- A docblock is at most two lines. One is the norm. If it does not fit in
two, it is not docblock material — cut it or move it to the commit message.
- All database access goes through a repository. No
DB:: and no model
queries in controllers, listeners, jobs or services. The single sanctioned
exception is a DataGrid's prepareQueryBuilder().
- Events are dot-delimited strings, not classes —
catalog.product.update.after
— and fire in before/after pairs. See laravel.md.
: binds a PHP value, :: passes a literal : through to Vue, and ::
only works on a Blade component tag. Getting this wrong fails silently. See
blade.md.
- Authorize on the server and escape at the point of interpolation. Hiding a
control is presentation; the route and the controller decide what is allowed,
and a value is safe in element text yet dangerous inside an attribute. See
security.md.
- Scope every storefront query to its owner. An id from the request never
selects a row on its own — that is the easiest real vulnerability to introduce
here. See security-authorization.md.
- Every user-facing string goes through
trans(), with the key added to all
22 locales and verified by php artisan bagisto:translations:check.
- Fix what you touch. A pre-existing violation in a file you edit is yours —
scan the whole class's member order and docblocks, not just your own lines.
Where the code and these files disagree
The checkout wins. Follow the surrounding code, say so in your summary, and
raise the drift — these files are a snapshot, not the source of truth.
That is different from a file that is simply wrong: a missing docblock in an
untouched class is debt, not a convention. Match the rule, not the worst
example of it.
Related
bagisto-code-review — applying all of this to someone else's change.
bagisto-package-development — the structure these rules are written inside.
1---2name: bagisto-coding-standards3description: Use when writing, changing or reviewing any Bagisto PHP or Blade — the conventions this codebase holds to, covering Laravel idiom, code style, comments and docblocks, database access, Blade, security and localization. Trigger phrases include "standards", "conventions", "code style", "docblock", "comments", "repository pattern", "blade", "component", "binding", "event", "migration", "security", "XSS", "authorization", "escaping", "is this safe", "best practice".4license: MIT5---67# Coding Standards89The canonical rules for all Bagisto code, in one place, so a change to a10DataGrid, a payment class or a theme is held to the same bar as a change to a11package.1213**Pint decides the mechanical questions.** Run `vendor/bin/pint` and trust it for14spacing, import order, trailing commas and the rest. What follows is what Pint15cannot see — and what a reviewer will otherwise send back.1617## Reference files1819| File | Load when |20|---|---|21| [code-style.md](code-style.md) | Writing any PHP — multi-clause conditions, class member order |22| [comments.md](comments.md) | Any comment or docblock, in any language |23| [laravel.md](laravel.md) | Framework idiom — events, migrations, config, helpers, validation, queues |24| [data-access.md](data-access.md) | Reading or writing the database — the repository rule and its one exception |25| [security.md](security.md) | Output, input, uploads, SQL, secrets, payments |26| [security-authorization.md](security-authorization.md) | Routes, permissions, guards, one user's access to another's data |27| [blade.md](blade.md) | Any `.blade.php` — namespaces, `:` versus `::`, components, page skeleton |28| [blade-formatting.md](blade-formatting.md) | Indentation, attribute layout, `@props` alignment, recipes |29| [localization.md](localization.md) | Any user-facing string, or a `Resources/lang/` change |3031The PHP rules apply inside an `@php` block too, which Pint cannot reach.3233## The rules in one screen3435- **Every method and property carries a docblock**, whatever its visibility. The36 description is a capitalised sentence ending in a full stop, and it is **at most37 two lines**. Type information belongs in the signature; add `@param`/`@return`38 only for what a native type cannot express.39- **Class members run constants → properties → constructor → public →40 protected → private**, each visibility one contiguous block. A helper called41 by a public method still lives in the protected block at the bottom.42- **A condition with more than one clause goes multiline**, the boolean operator43 leading each line. Single-clause conditions stay inline. The rule keys off the44 number of clauses, not the line length.45- **No comments inside method bodies**, object literals or markup — not even a46 one-line "why". A non-obvious reason belongs in the method's docblock or the47 commit message. If a line needs prose to be understood, extract a named48 method instead. See [comments.md](comments.md).49- **No docblock above the class**, ever — 98.7% of core classes have none. The50 docblock belongs on the method, property or constant, never on the class,51 interface, trait or enum.52- **A docblock is at most two lines.** One is the norm. If it does not fit in53 two, it is not docblock material — cut it or move it to the commit message.54- **All database access goes through a repository.** No `DB::` and no model55 queries in controllers, listeners, jobs or services. The single sanctioned56 exception is a DataGrid's `prepareQueryBuilder()`.57- **Events are dot-delimited strings**, not classes — `catalog.product.update.after`58 — and fire in `before`/`after` pairs. See [laravel.md](laravel.md).59- **`:` binds a PHP value, `::` passes a literal `:` through to Vue**, and `::`60 only works on a Blade component tag. Getting this wrong fails silently. See61 [blade.md](blade.md).62- **Authorize on the server and escape at the point of interpolation.** Hiding a63 control is presentation; the route and the controller decide what is allowed,64 and a value is safe in element text yet dangerous inside an attribute. See65 [security.md](security.md).66- **Scope every storefront query to its owner.** An id from the request never67 selects a row on its own — that is the easiest real vulnerability to introduce68 here. See [security-authorization.md](security-authorization.md).69- **Every user-facing string goes through `trans()`**, with the key added to all70 22 locales and verified by `php artisan bagisto:translations:check`.71- **Fix what you touch.** A pre-existing violation in a file you edit is yours —72 scan the whole class's member order and docblocks, not just your own lines.7374## Where the code and these files disagree7576The checkout wins. Follow the surrounding code, say so in your summary, and77raise the drift — these files are a snapshot, not the source of truth.7879That is different from a file that is simply wrong: a missing docblock in an80untouched class is debt, not a convention. Match the *rule*, not the worst81example of it.8283## Related8485- **`bagisto-code-review`** — applying all of this to someone else's change.86- **`bagisto-package-development`** — the structure these rules are written inside.