PHPackages                             sinemacula/coding-standards-laravel - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. sinemacula/coding-standards-laravel

ActivePhpcodesniffer-standard[Testing &amp; Quality](/categories/testing)

sinemacula/coding-standards-laravel
===================================

Laravel-specific coding standards, static-analysis rules, and code-quality tooling for Sine Macula's Laravel repositories.

v1.3.0(1mo ago)01.5k6Apache-2.0PHP ^8.3

Since Jun 21Compare

[ Source](https://github.com/sinemacula/coding-standards-laravel)[ Packagist](https://packagist.org/packages/sinemacula/coding-standards-laravel)[ RSS](/packages/sinemacula-coding-standards-laravel/feed)WikiDiscussions Synced 2w ago

READMEChangelog (8)Dependencies (11)Versions (8)Used By (6)

Coding Standards (Laravel)
==========================

[](#coding-standards-laravel)

[![Latest Stable Version](https://camo.githubusercontent.com/19c04489f78cbafce1507a7e56c39dee32af575e83ec115a94dbfad8e73ad749/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f73696e656d6163756c612f636f64696e672d7374616e64617264732d6c61726176656c2e737667)](https://packagist.org/packages/sinemacula/coding-standards-laravel)[![Build Status](https://github.com/sinemacula/coding-standards-laravel/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/sinemacula/coding-standards-laravel/actions/workflows/tests.yml)[![Quality Gates](https://github.com/sinemacula/coding-standards-laravel/actions/workflows/quality-gates.yml/badge.svg?branch=master)](https://github.com/sinemacula/coding-standards-laravel/actions/workflows/quality-gates.yml)[![Maintainability](https://camo.githubusercontent.com/4f33e3f40becc122342fc1653f71ed6ba00d281434deb3d411e8bba221f274f1/68747470733a2f2f716c74792e73682f67682f73696e656d6163756c612f70726f6a656374732f636f64696e672d7374616e64617264732d6c61726176656c2f6d61696e7461696e6162696c6974792e737667)](https://qlty.sh/gh/sinemacula/projects/coding-standards-laravel)[![Code Coverage](https://camo.githubusercontent.com/3a3d3c470a1b94f34c1c2b77920bf43a69a6c2b9927e5785c36b876401f96552/68747470733a2f2f716c74792e73682f67682f73696e656d6163756c612f70726f6a656374732f636f64696e672d7374616e64617264732d6c61726176656c2f636f7665726167652e737667)](https://qlty.sh/gh/sinemacula/projects/coding-standards-laravel)[![Total Downloads](https://camo.githubusercontent.com/6b1e66912f9d8740c46a3ef5e4569435c033ed7b8a93dcca1773a5bc9eceb86a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f73696e656d6163756c612f636f64696e672d7374616e64617264732d6c61726176656c2e737667)](https://packagist.org/packages/sinemacula/coding-standards-laravel)

Laravel-specific coding standards, static-analysis rules, and code-quality tooling for Sine Macula's Laravel repositories.

Install this **only in Laravel projects**. Framework-agnostic, language-wide standards live in [`sinemacula/coding-standards`](https://github.com/sinemacula/coding-standards); this package adds the Laravel-specific layer. Non-Laravel repos simply don't install it - that is how the Laravel rules stay scoped to Laravel projects (no runtime framework detection).

Installation
------------

[](#installation)

```
composer require --dev sinemacula/coding-standards-laravel
```

This brings `sinemacula/coding-standards` with it. You also need `squizlabs/php_codesniffer`, `dealerdirect/phpcodesniffer-composer-installer`, and `slevomat/coding-standard` in your dev deps (as you already do for the base standard).

Usage
-----

[](#usage)

Wire it into the PHP tools through the same Qlty plugin setup you already use for the base standard (`package_file = "composer.json"` with `package_filters = ["sinemacula", ...]` in `.qlty/qlty.toml` - the `"sinemacula"` filter already matches this package, so Qlty installs it into the linter tool environments automatically).

### PHPCS

[](#phpcs)

Two standards ship; reference exactly one (each pulls in `SineMacula`, so it replaces it - don't reference both):

- **`SineMaculaLaravel`** - for applications. The full standard, including the role-based structure rules (placement and naming of controllers, models, providers, …) and the controller rules.
- **`SineMaculaLaravelPackage`** - for libraries and packages. The same standard with the app-skeleton rules (`Structure.*`, `Controllers.*`) excluded, since a package is organised by domain rather than Laravel's app directory layout. Composition only - it redefines nothing.

```

    src
    tests

```

### PHPStan

[](#phpstan)

The Laravel rules are auto-included via this package's `extra.phpstan.includes` (resolved by `phpstan/extension-installer`), alongside the base config. Your project's `phpstan.neon` only needs its own `level` / `paths`.

### PHP CS Fixer

[](#php-cs-fixer)

If Laravel-specific fixer rules are present, reference the Laravel factory from your `.php-cs-fixer.dist.php`; otherwise keep using the base `PhpCsFixerConfig::make()`.

Rules
-----

[](#rules)

These are the Laravel-specific rules this package adds on top of the base `sinemacula/coding-standards`. A deliberate exception can be bypassed with the native directive - `// phpcs:ignore ` for a sniff, `@phpstan-ignore ` for a rule.

### PHPCS sniffs

[](#phpcs-sniffs)

SniffEnforces`SineMaculaLaravel.Architecture.DisallowServiceLocation`No service location (`app()`, `resolve()`, `App::make()`) inside a class body - inject collaborators instead. Targets production code: test files, container-wiring classes (service providers and registrars), and dynamic resolution of a runtime variable (`app($class)`, a factory that cannot be injected) are exempt.`SineMaculaLaravel.Configuration.DisallowEnvOutsideConfig``env()` only inside `config/` files (test code exempt); use `config()` everywhere else.`SineMaculaLaravel.Controllers.DisallowDatabaseAccess`No `DB::` facade or direct Eloquent model queries in a controller - read through a repository.`SineMaculaLaravel.Controllers.DisallowInlineValidation`No inline validation (`$request->validate()`, `Validator::make()`) in a controller - use a form request.`SineMaculaLaravel.Controllers.DisallowNonRestActions`A controller's candidate actions (public, non-static instance methods) must be REST verbs or `__invoke`; statics, the constructor and framework overrides are auto-exempt. Mark a method `@non-rest-action` (a deliberate non-CRUD action) or `@utility` (not an action) to allow it.`SineMaculaLaravel.Debug.DisallowDebugStatements`No debug calls (`dd`, `dump`, `ray`, `var_dump`, `print_r`) in committed code.`SineMaculaLaravel.Eloquent.DisallowLegacyAttributeAccessor`No legacy `getXAttribute()` / `setXAttribute()` accessors on an Eloquent model - use `Attribute::make()`. Gated on both model identity (base class) and accessor arity, so look-alike methods on other classes are clean.`SineMaculaLaravel.Services.DisallowHttpAbort`No `abort()` / `abort_if` / `abort_unless` / `HttpException` in a service - throw a domain exception.`SineMaculaLaravel.Structure.RequireBladeLocation`A `*.blade.php` template must live under a `resources/views` (or module `Resources/views`) directory.`SineMaculaLaravel.Structure.RequireRoleDirectory`A class whose role is recognised by identity (what it extends/implements) must live under that role's directory - a controller under `Http/Controllers`; an entry-point provider may sit at the package root.`SineMaculaLaravel.Structure.RequireRoleNaming`A class is named for its role: controllers/providers/form-requests/resources/policies require a suffix, models forbid `Model`/`Entity`, and the rest (jobs, listeners, events, mailables, middleware, commands, casts, rules) stay bare.`SineMaculaLaravel.Structure.RoutesLocation`A `routes.php` file, if present, must sit at the root of an `Http` directory.`SineMaculaLaravel.TypeHints.PropertyTypeHint`A class property declares a native type - except the framework-magic properties (`$table`, `$fillable`, `$signature`, …, the configurable `magicProperties` set) that override an untyped parent and so cannot be typed.`SineMaculaLaravel.TypeHints.ParameterTypeHint`A function or method parameter declares a native type - except where a parent fixes the signature: a method carrying `#[\Override]`, or a non-private trait method (whose effective parent is the consuming class's, invisible to a token sniff).`SineMaculaLaravel.TypeHints.ReturnTypeHint`A function, method or closure declares a native return type - except constructors/destructors/clone handlers and methods carrying `#[\Override]`.#### Role-based structure

[](#role-based-structure)

`RequireRoleNaming` and `RequireRoleDirectory` resolve a class's role by **identity first** - what it `extends`, `implements`, `use`s or is attributed with - and fall back to its **location** (a concrete class under a role directory, minus exempt sub-namespaces such as `Concerns`/`Support`/`Contracts`). A class with neither is unconstrained, so genuine domain classes are never flagged.

The default role table is convention-correct for Laravel: it never requires a suffix the framework leaves bare, and the idiomatic bare `User` model is honoured (the `Model` role's identity covers `Authenticatable` and `Pivot`). Every list - `roleIdentities`, `roleLocations`, `requireSuffix`, `forbidSuffix`, `exemptNamespaces`, `moduleRootRoles` - is a public sniff property a ruleset can override. Identity is matched on the immediate base by short name, so a project's own intermediate base (e.g. a `BaseController`) is supported by adding it to `roleIdentities`. An identity entry containing `\` instead matches the qualified name resolved through the file's imports, which keeps same-named traits distinct: the `Job` role's `Bus\Dispatchable` entry identifies a sync job without ever matching the Events `Dispatchable` an idiomatic event uses. Test classes - by name, test-case base, or a `tests/` path - play no role at all, so a test mirroring a role namespace (`Tests\Unit\Policies\...`) is never constrained.

Opt a class out entirely with an `@role-exempt` docblock tag or a `#[NotARole]` attribute (matched by short name; `SineMacula\CodingStandardsLaravel\Attributes\NotARole` ships so the reference also resolves under static analysis). Both hatches work with other attributes present on the class.

#### Type hints

[](#type-hints)

The `TypeHints.*` sniffs replace the base standard's Slevomat native-type requirements with Laravel-aware equivalents (the base Slevomat `MissingNativeTypeHint` / `MissingAnyTypeHint` codes are excluded; the traversable-specification checks are kept). They are needed because the Slevomat sniffs are inheritance-blind: PHP forbids typing a property that overrides an untyped parent (`$table`, `$fillable`, …) or changing an inherited method signature, so the original rules force types that fatal at class load. Native types are still required everywhere else. The exempt property set is the configurable `magicProperties` list on `PropertyTypeHint`, and an overriding method opts its signature out with the native `#[\Override]` attribute. A non-private trait method is also exempt from the parameter requirement, since its effective parent is whatever the consuming class extends and a token sniff cannot resolve that.

#### Readonly properties

[](#readonly-properties)

The base standard requires every public property to be `readonly`. An Eloquent model is exempt: it overrides the framework's public magic properties (`$timestamps`, `$incrementing`, …), which are declared non-readonly on the base class, and PHP forbids making an inherited property readonly. This standard sets the base sniff's `ignoredParentClasses` to the model bases (`Model`, `Authenticatable`, `Pivot`), matched by the immediate parent name as written.

### PHPStan rules

[](#phpstan-rules)

IdentifierEnforces`sineMaculaLaravel.castsProperty`No `$casts` property on an Eloquent model (a class extending `Model`/`Authenticatable`/`Pivot`) - use the `casts()` method. A non-model class with its own `$casts` is left alone.`sineMaculaLaravel.datesProperty`No `$dates` property on a model (deprecated) - cast dates via `casts()`.`sineMaculaLaravel.massAssignment`Every concrete production model declares mass assignment explicitly via `$fillable`/`$guarded` or the `#[Fillable]`/`#[Guarded]` attribute; models declared in tests are exempt.`sineMaculaLaravel.relationshipReturnType`A relationship method declares a return-type hint.`sineMaculaLaravel.modelAttribute`Prefer a model attribute over its legacy property/method form, for the attributes a project enables (default `#[Table]`/`#[Fillable]`/`#[Hidden]`, configurable via `sineMaculaLaravel.modelAttributes`). The 13.2-only attributes are enforced only when the project's Laravel floor reaches 13.2 - taken from `sineMaculaLaravel.minLaravelVersion` or detected from the nearest `composer.json`; below that, or when undetectable, the property form is left alone.`sineMaculaLaravel.migrationMethods`A migration defines both `up()` and `down()`.`sineMaculaLaravel.schemaNaming`Table and column names in a migration use snake\_case. Inspects the literal name arguments of the `Schema` table calls and the Blueprint column/index methods (value arguments and dynamic names are left alone). Digits are allowed (`line_1`, `oauth2`); only casing is enforced.`sineMaculaLaravel.formRequestRules`A form request (under `Http\Requests`) defines a `rules()` method. Classes declared in tests, where the namespace merely mirrors the production tree, are exempt.`sineMaculaLaravel.factoryTimestamps`A factory `definition()` must not set `created_at` / `updated_at`.`sineMaculaLaravel.resourceFieldNaming`Field keys in a resource's `toArray()` result use snake\_case, nested arrays included. Inspects the string-literal keys of the array returned directly from `toArray()` on a `JsonResource`; computed keys, a non-literal return, and non-resource classes are left alone. Digits are allowed (`line_1`); only casing is enforced.Requirements
------------

[](#requirements)

- PHP ^8.3

Testing
-------

[](#testing)

```
composer test                # PHPUnit sniff/rule suite
composer test:coverage       # suite with Clover coverage output (requires Xdebug)
composer test:mutation       # Infection mutation gate (min MSI 90)
composer test:mutation:full  # full mutation suite without thresholds
composer analyse             # PHPStan over the package's own sniffs and rules
composer check               # static analysis and lint via qlty
composer format              # format via qlty
composer smells              # duplication / complexity smells via qlty
```

Changelog
---------

[](#changelog)

See [CHANGELOG.md](CHANGELOG.md) for a list of notable changes.

Contributing
------------

[](#contributing)

Contributions are welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on branching, commits, code quality, and pull requests.

Security
--------

[](#security)

If you discover a security vulnerability, please report it responsibly. See [SECURITY.md](SECURITY.md) for the disclosure policy and contact details.

License
-------

[](#license)

Licensed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0).

###  Health Score

46

—

FairBetter than 92% of packages

Maintenance91

Actively maintained with recent releases

Popularity21

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

6

Last Release

43d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/6262ea965c244b0c946a2f29a94da05e30846c066a0b59399466216654c78fe6?d=identicon)[sinemacula](/maintainers/sinemacula)

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/sinemacula-coding-standards-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/sinemacula-coding-standards-laravel/health.svg)](https://phpackages.com/packages/sinemacula-coding-standards-laravel)
```

###  Alternatives

[symfony/symfony

The Symfony PHP framework

31.4k87.4M2.2k](/packages/symfony-symfony)[matomo/matomo

Matomo is the leading Free/Libre open analytics platform

21.7k39.6k](/packages/matomo-matomo)[phan/phan

A static analyzer for PHP

5.6k12.1M1.3k](/packages/phan-phan)[craftcms/cms

Craft CMS

3.6k3.7M3.3k](/packages/craftcms-cms)[api-platform/core

Build a fully-featured hypermedia or GraphQL API in minutes!

2.6k52.2M366](/packages/api-platform-core)[statamic/cms

The Statamic CMS Core Package

4.9k3.8M1.1k](/packages/statamic-cms)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
