Files
pl_mail/phpstan.dist.neon

115 lines
5.2 KiB
Plaintext

# Static analysis.
#
# Level 5 with everything already failing captured in a baseline. The
# alternative — level 0 with no baseline — reports nothing interesting, and
# level 9 buys a fortnight of triage before it finds its first real bug. Five is
# where the class of defect this codebase actually has starts showing up:
# nullable entity getters (`?int getId()`, `?Account getAccount()`) flowing into
# parameters and return types that are not nullable.
#
# The baseline is a debt ledger, not a licence. It shrinks; raise the level when
# it is small enough that doing so is a day's work rather than a fortnight's.
includes:
- phpstan-baseline.neon
- vendor/phpstan/phpstan-symfony/extension.neon
- vendor/phpstan/phpstan-symfony/rules.neon
- vendor/phpstan/phpstan-doctrine/extension.neon
- vendor/phpstan/phpstan-doctrine/rules.neon
parameters:
level: 5
# The whole project rather than just src/ and tests/: bin/, config/ and
# public/ hold real PHP that can break the same way anything else does —
# config/bootstrap_generated_secrets.php is loaded into every process
# through composer's autoload.files.
#
# Listed explicitly rather than as `./`, and that is not a style
# preference. PHPStan walks the tree with a RecursiveDirectoryIterator
# *before* it applies excludePaths, so a directory it cannot read is a hard
# crash rather than a skip — and no exclusion can prevent it, because the
# crash happens during enumeration. `.claude/worktrees` holds entire git
# worktrees of this repository (37 of them at the time of writing), several
# containing a root-owned `var/secrets` left by a container. With `./` the
# gate could not be run at all from a working checkout: it died on a
# directory belonging to a different checkout of itself.
#
# Everything with PHP in it is named below. A new top-level directory that
# holds code has to be added here, which is the cost of this; the previous
# arrangement's cost was that the command did not run.
paths:
- bin
- config
- public
- src
- tests
- importmap.php
# Read for its classes, not analysed: migrations are generated and nobody
# edits them by hand, but a test that runs one (tests/Migrations) names its
# class, and without this that is a class PHPStan has never heard of.
scanDirectories:
- migrations
excludePaths:
analyseAndScan:
# Not PHP.
- assets
- docs
- frankenphp
- templates
- translations
# Third-party code, and its symbols come from the autoloader
# anyway — analysing it reports other people's debt.
- vendor
- node_modules (?)
# Build and run artefacts. public/assets is compiled output and
# var/ holds the container dumps this very config reads.
#
# The `(?)` marks a path that may legitimately be absent: PHPStan
# treats an excludePath that matches nothing as a config error, and
# none of these exist on a fresh clone or in a CI job that has not
# built assets yet.
- public/assets (?)
- public/bundles (?)
- var (?)
- playwright (?)
- playwright-report (?)
- test-results (?)
# Generated: a ~1000-line dump of the framework config tree that
# exists to be read. (migrations/ is not analysed either, by not
# being in `paths`; see scanDirectories.)
- config/reference.php (?)
# Twig extensions lifted from upstream rather than written here.
# NOTE: only Vendor/ — the rest of src/Twig is application code
# (SidebarCounts and friends) and must stay analysed.
- src/Twig/Vendor
# ignoreErrors is deliberately empty.
#
# The rule usually wanted here — silencing "Property …::$id (int|null) is
# never assigned int" on Doctrine identifiers — is not needed: the
# phpstan-doctrine extension included above already understands that the
# ORM assigns identifiers by reflection, so the error never fires. Adding
# the pattern anyway would fail the build, because PHPStan treats an ignore
# that matches nothing as a config error.
#
# What property.onlyWritten does catch in this project is a different and
# genuine thing: controllers injecting repositories they never use
# (MailController::$mailboxRepository, ComposeController::$mailboxRepository
# and about fifteen more). Those are in the baseline as debt to delete, not
# noise to suppress — which is why there is no blanket ignore for them.
ignoreErrors: []
# Docblocks here are prose as much as types — plenty predate the signatures
# beside them. Trusting them as certain turns a stale @var into a stream of
# "condition is always false" on code that is fine.
treatPhpDocTypesAsCertain: false
symfony:
containerXmlPath: var/cache/test/App_KernelTestDebugContainer.xml
consoleApplicationLoader: tests/phpstan-console-loader.php
doctrine:
objectManagerLoader: tests/phpstan-object-manager.php