paysera/lib-php-cs-fixer-config
Shared PHP CS Fixer configuration from Paysera that enforces a consistent coding style across PHP projects. Install via Composer and extend the provided ruleset to standardize formatting and keep your codebase clean.
Install as a dev dependency. It only affects tooling, so keep it out of production builds:
composer require --dev paysera/lib-php-cs-fixer-config friendsofphp/php-cs-fixer
The package does not bundle a binary; friendsofphp/php-cs-fixer is still the executable you run.
Inspect what the package exports first. Config packages are usually tiny — open vendor/paysera/lib-php-cs-fixer-config/src/ and look for the factory/config class (commonly ConfigFactory, PhpCsFixerConfigFactory, or a Config subclass). That single class is the entire public surface you will interact with day-to-day, so confirm its method names before writing your config.
Create a .php-cs-fixer.dist.php at the project root that delegates to the package and supplies your Finder:
<?php
use PhpCsFixer\Finder;
use Paysera\PhpCsFixerConfig\ConfigFactory; // confirm actual FQCN
$finder = Finder::create()
->in([__DIR__ . '/src', __DIR__ . '/tests'])
->exclude(['vendor', 'var', 'storage'])
->name('*.php')
->notName('*.blade.php');
return ConfigFactory::create()
->setFinder($finder);
Run a dry run before touching anything. This is the first real use case: see how far your codebase is from Paysera conventions without rewriting files.
vendor/bin/php-cs-fixer fix --dry-run --diff --using-cache=no
Then fix in a single isolated commit. Commit the mechanical reformat separately from any feature work so it can be listed in .git-blame-ignore-revs.
One canonical config, committed to VCS. Name it .php-cs-fixer.dist.php and only commit .php-cs-fixer.php locally when you need to experiment. This keeps every developer and CI on the identical ruleset produced by the package.
Override rules per project, not per file. The config object is mutable — clone it and layer on top:
$config = ConfigFactory::create()->setFinder($finder);
$rules = $config->getRules();
$rules['ordered_imports'] = ['sort_algorithm' => 'alpha'];
// or disable a Paysera rule that fights your framework
return $config->setRules($rules);
setRules() replaces the entire rule set, so always read getRules() first.
Separate finders for different concerns. Typical split: src/ with strict rules, tests/ with a relaxed set (e.g. allow @test annotation formatting, unused imports in fixtures). Build two Config instances in one file and run the fixer twice, or drive them from separate composer scripts.
Composer scripts for team ergonomics. Nobody remembers the flags:
"scripts": {
"cs:check": "php-cs-fixer fix --dry-run --diff --using-cache=no",
"cs:fix": "php-cs-fixer fix"
}
CI gate using dry-run. The check must fail the build on any diff. Treat the diff output as the developer-facing error message — --diff and --show-progress=none keep logs readable:
vendor/bin/php-cs-fixer fix --dry-run --diff --format=checkstyle > cs-report.xml
Pre-commit hook for fast feedback. Wire the same command into captainhook, lefthook, or a Husky task so violations are caught before push. Keep the hook scoped to staged files (--path-mode=intersection with a file list) so it stays fast on large repos.
Editor integration via the same config. PHPStorm's "PHP CS Fixer" inspection and VS Code's junstyle.php-cs-fixer extension both accept the path to .php-cs-fixer.dist.php. Because the rules live in the package, every editor and the CI pipeline stay in sync automatically — this is the main leverage of a shared config package.
Monorepo usage. Place a single root .php-cs-fixer.dist.php with a Finder that walks all packages/*/src, or expose the factory from a shared internal package that other sub-projects require — you avoid duplicating rule tweaks in every package.
Version compatibility with php-cs-fixer is the #1 pitfall. The package pins or expects a specific friendsofphp/php-cs-fixer major (v3 vs. v4 differ in rule names and config API). Let Composer resolve it, run composer why friendsofphp/php-cs-fixer, and do not upgrade the fixer independently of this package — rule names like ordered_imports and behavior of @PhpCsFixer sets change between majors.
PHP runtime mismatch. PHP CS Fixer parses/refactors against the runtime PHP version plus the config's setRiskyAllowed()/PHP version target. If your CI container runs a newer PHP than the package was tested against, you may see parse errors on newer syntax. Pin the CI PHP version to the one the package's composer.json declares.
Risky rules are opt-in. If the package's ruleset includes risky fixes, they only apply when ->setRiskyAllowed(true) is set on the config (or the factory already sets it). If --dry-run reports nothing but you expected changes, check this flag first.
setRules() is destructive, not additive. The most common debugging mistake: calling ->setRules([...]) on the returned config and silently dropping all Paysera rules. Always merge into getRules().
Caching bites during upgrades. After bumping the package or the fixer, run with --using-cache=no once — the .php-cs-fixer.cache can hide newly applied rules on unchanged files.
Finder exclusions must be explicit. vendor/, node_modules/, generated code, and .blade.php files are not excluded by default. Also exclude migration files if you do not format legacy code, otherwise you generate huge unrelated diffs.
Parallel runs and memory. On large codebases, PHP_CS_FIXER_PARALLEL=1 (env) or --sequential toggles behavior; parallel mode can cause nondeterministic fixes when rules interact (e.g. import ordering plus class attribute sorting). If output differs run-to-run, fall back to sequential while you diagnose.
Diff noise on first adoption. Budget a dedicated PR. Add the commit to .git-blame-ignore-revs so git blame skips it, and communicate the freeze window to the team.
Extension points are thin by design. The package is a ruleset, not a framework. When you need project-specific behavior, wrap it in your own MyCompanyCsFixerConfigFactory that calls the Paysera factory and applies overrides — do not fork the package. That wrapper is also the right place to centralize PHP-version-conditional rules.
Debugging a specific fix. --rules=<rule_name> combined with --dry-run --diff isolates a single rule without changing config, and -vvv shows which rule produced each hunk. Useful when a Paysera rule conflicts with a framework idiom (e.g. Doctrine annotation formatting).
Low ecosystem signal. With ~10 stars and no public repo reference, the package is effectively internal Paysera tooling. Read the source (it is a few files) before adopting; expect no community answers for edge cases, and pin to an exact version in composer.json since releases can change the ruleset wholesale.
How can I help you explore Laravel packages today?