Configuration¶
The package has two config files to extend from mago.toml, see Install:
drupal.mago.tomlmakes Mago match Drupal's standard, for a site, a module or a theme.drupal-core.mago.tomladds what core'sphpcs.xml.distchecks, for a core checkout.
Each setting in the files has a comment that says why it's there.
What drupal.mago.toml sets¶
- Drupal's PHP file extensions, and
ymlfor the rules for info and routing files. Other YAML files aren't read, and the formatter and the analyzer stay out of the info and routing files. - The worker, with Xdebug and pcov off, see Xdebug and pcov.
- Mago's
drupalformatter preset, and itsdrupallinter integration, which acceptsTRUE,FALSEandNULL. - The
InterfaceandTraitsuffixes, and thefile-namerule, as Coder 9 checks them. minimum-fail-level = "warning"for the linter, so that a warning fails the run as it does in phpcs, see What fails a run.- Coder's level for the Mago rules that stand in for a sniff, such as
class-nameandarray-style. Mago reports them as help or as a note, which doesn't fail a run. check-name-casingfor the analyzer, which portsSquiz.PHP.LowercasePHPFunctions. The analyzer stays out of*.api.phpfiles and test fixtures, as phpstan-drupal does.- Mago's rules that contradict the standard or repeat a rule of this extension, turned off, such
as
tagged-todoandfunction-name. The same goes for advice that the standard doesn't ask for, such asno-else-clauseandstrict-types. Turning them off doesn't lose any check done by phpcs. - Excludes for the paths where a Mago rule reports what Drupal does on purpose, such as the fake
credentials in tests. The linter also skips
.ht.router.php, as phpcs skips a file whose name starts with a dot.
It doesn't set php-version, since that's up to the project. Without it, Mago assumes its newest
PHP version, and the formatter writes syntax that older versions reject, such as new Foo()->bar().
Changing a setting¶
The project's mago.toml wins over the file that it extends. A table is merged into the one in the
file, so one line changes one rule. An array is added to the one in the file. The worker command is
replaced as a whole.
extends = "vendor/drupal/mago/drupal.mago.toml"
php-version = "8.3"
[source]
# Coder also checks .test files, a Drupal 7 format.
extensions = ["test"]
[linter.rules]
strict-types = { enabled = true }
[analyzer]
# Let @phpstan-ignore comments drop the Mago issues that report the same finding.
plugins = ["phpstan-ignores"]
See PHPStan ignores for the plugin.
Turning rules off¶
Mago takes this extension's rule codes under [linter.rules], with the same enabled, level and
exclude settings as its own rules. Quote the code, because it holds a /:
[linter.rules]
"drupal/inline-comment-punctuation" = { enabled = false }
"drupal/missing-function-comment" = { exclude = ["tests/"] }
"drupal/else-if" = { level = "warning" }
enabled = false turns a rule off. exclude leaves the rule out of the matching paths, which take
the same globs and directory prefixes as the excludes of Mago's own rules. level sets the level of
every issue that the rule reports.
A rule that is turned off still runs when mago lint --only names it, and mago lint --pedantic
doesn't read these settings. Mago warns about a code that doesn't name a rule, and the run goes on.
A project that turns phpcs sub-codes off in its phpcs.xml can turn off the matching rules this
way. Coming from Coder says which rule ports each sub-code.
[linter.rules] takes only linter rules. To turn off an analyzer check,
use Mago's own [analyzer] ignore, for the whole project or for some paths:
[analyzer]
ignore = [
"drupal/global-drupal-call",
{ code = "drupal/entity-storage-injection", in = "src/Legacy/" },
]
An entry with a pattern drops the issues whose text matches a regular expression. The text is the
message, the notes, the help and the annotations of the issue. code and in narrow the entry
further:
[analyzer]
ignore = [
{ code = "unsafe-instantiation", pattern = "new static\\(\\)" },
]
What fails a run¶
phpcs exits with an error when it reports a warning or an error. mago lint on its own fails only
on an error, and many of its rules report a warning, help or a note. drupal.mago.toml sets
minimum-fail-level = "warning", and gives the Mago rules that stand in for a Coder sniff the level
used by Coder. So a report that fails phpcs fails mago lint too.
The Mago rules that are on and don't port any sniff, such as strict-behavior and str-contains,
fail the run as well when they report a warning. Turn a rule off, or set its level, in the
project's mago.toml:
[linter]
# Fail on errors only.
minimum-fail-level = "error"
[linter.rules]
strict-behavior = { level = "help" }
mago analyze has its own minimum-fail-level under [analyzer], which isn't set by
drupal.mago.toml.
Checking Drupal core¶
drupal-core.mago.toml is for a core checkout. It extends drupal.mago.toml and adds:
- The files that core's
phpcs.xml.distchecks:core/andcomposer/, with.testfiles, andvendor/read for its symbols. - The files that phpcs doesn't check, left out of the formatter and the linter: the paths excluded
by
phpcs.xml.dist, and the files marked with// phpcs:ignoreFileor// @codingStandardsIgnoreFile, which Mago's own rules don't read. - The classes that core's
phpstan.neon.distleaves out because they're broken on purpose, left out of the analyzer. The one that Mago reports asemanticserror for is left out of the linter too, since that error doesn't have a rule to turn off. - The worker with
--phpcs-ignoresand--phpstan-ignores, so that core's phpcs and PHPStan comments drop the issues of the extension's rules, see phpcs and PHPStan comments. - The rules and the analyzer checks that core doesn't run, turned off.
Which rules are off¶
Core's own phpcs.xml.dist asks for less than Drupal's standard. drupal-core.mago.toml follows
the file of Drupal 11.x, which runs Coder 9, and turns off the rules whose checks core turns off or
doesn't run, Mago's own rules included. That covers Mago's general advice, such as
strict-behavior and inline-variable-return, which doesn't port any sniff that core runs. Where
phpcs.xml.dist leaves paths out of a sniff, such as the tests directories out of the line length
check, the file leaves them out of the rules that port it. It also ignores five analyzer checks
that are about modules that use core's API. The comments in the file say why.
A rule that stays on can check more than the sniff that it ports, such as drupal/hook-comment on
a #[Hook] method and drupal/doc-see-tag in a class docblock. Those reports fail the run on
core, where phpcs passes.
A rule that the file turns off can be turned back on in the checkout's mago.toml:
extends = "vendor/drupal/mago/drupal-core.mago.toml"
php-version = "8.3"
[linter.rules]
"drupal/inline-comment-punctuation" = { enabled = true }
An analyzer check stays ignored, since Mago adds the ignore list of mago.toml to the one of the
file that it extends.
Two rules follow core's directories by themselves, since a rule's exclude setting can't name the
only directories to check. In the files of Drupal core itself, missing-summary and
missing-function-comment run only in the directories where core's phpcs.xml.dist runs them. A
file is core's when one of its directories is named core and holds lib/Drupal.php.
drupal/unknown-service checks every service id in
core's files, since core looks up only its own services.
A project that starts from core's phpcs.xml.dist but isn't core can copy the [linter.rules]
entries of drupal-core.mago.toml, see Turning rules off.