{"id":48906212,"url":"https://github.com/iwf-web/phpstan-rules","last_synced_at":"2026-04-16T20:06:55.256Z","repository":{"id":351307255,"uuid":"1176925297","full_name":"iwf-web/phpstan-rules","owner":"iwf-web","description":"Custom rules for PHPStan for applications developed by IWF","archived":false,"fork":false,"pushed_at":"2026-04-14T14:21:07.000Z","size":49,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-14T14:26:33.329Z","etag":null,"topics":["php","phpstan","phpstan-rules","standards"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/iwf-web.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-09T14:16:40.000Z","updated_at":"2026-04-14T14:21:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/iwf-web/phpstan-rules","commit_stats":null,"previous_names":["iwf-web/phpstan-rules"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/iwf-web/phpstan-rules","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iwf-web%2Fphpstan-rules","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iwf-web%2Fphpstan-rules/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iwf-web%2Fphpstan-rules/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iwf-web%2Fphpstan-rules/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iwf-web","download_url":"https://codeload.github.com/iwf-web/phpstan-rules/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iwf-web%2Fphpstan-rules/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31902182,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-16T18:22:33.417Z","status":"ssl_error","status_checked_at":"2026-04-16T18:21:47.142Z","response_time":69,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["php","phpstan","phpstan-rules","standards"],"created_at":"2026-04-16T20:06:54.330Z","updated_at":"2026-04-16T20:06:55.250Z","avatar_url":"https://github.com/iwf-web.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# IWF PHPStan Rules\n\nCustom PHPStan rules used across IWF projects to enforce coding standards, security practices, and architectural conventions.\n\n[![License](https://img.shields.io/github/license/iwf-web/phpstan-rules)][license]\n[![Version](https://img.shields.io/packagist/v/iwf-web/phpstan-rules?label=latest%20release)][packagist]\n[![Version (including pre-releases)](https://img.shields.io/packagist/v/iwf-web/phpstan-rules?include_prereleases\u0026label=latest%20pre-release)][packagist]\n[![Downloads on Packagist](https://img.shields.io/packagist/dt/iwf-web/phpstan-rules)][packagist]\n[![Coverage](https://sonar.iwf.io/api/project_badges/measure?project=phpstan-rules\u0026metric=coverage\u0026token=sqb_711e9e62f13d6a2ffedc78e2e4ce597e86a0108c)](https://sonar.iwf.io/dashboard?id=phpstan-rules)\n\n## Requirements\n\n- PHP 8.3 or higher\n- PHPStan ^2.1\n\n## Installation\n\n```bash\ncomposer require --dev iwf-web/phpstan-rules\n```\n\n## Usage\n\nInclude the rule set in your `phpstan.neon` or `phpstan.neon.dist`:\n\n```neon\nincludes:\n    - vendor/iwf-web/phpstan-rules/rules.neon\n```\n\n### Configuration\n\nSeveral rules require or accept configuration parameters under the `iwf` key.\n\n#### Controller rules\n\n```neon\nparameters:\n    iwfWeb:\n        controller:\n            controllerNamespace: 'App\\Controller'\n            excludedNamespaces: []\n            excludedControllers:\n                - 'App\\Controller\\Api\\Security\\LoginController'\n```\n\n#### Required use aliases\n\nEnforce that specific namespaces are always imported with a defined alias:\n\n```neon\nparameters:\n    iwfWeb:\n        requiredUseAlias:\n            aliasDefinitions:\n                - { namespace: 'Doctrine\\ORM\\Mapping', alias: 'ORM' }\n                - { namespace: 'Symfony\\Component\\Validator\\Constraints', alias: 'Assert' }\n```\n\n#### Attribute requirements\n\nEnforce that certain attributes may only appear alongside required companion attributes:\n\n```neon\nparameters:\n    iwfWeb:\n        attributeRequirements:\n            attributeDefinitions:\n                -\n                    attribute: 'Symfony\\Component\\Routing\\Attribute\\Route'\n                    requires:\n                        - 'OpenApi\\Attributes\\Tag'\n                        - 'Symfony\\Component\\Security\\Http\\Attribute\\IsGranted'\n```\n\n#### Force DateProvider (requires `coala/date-provider-bundle`)\n\n```neon\nparameters:\n    iwfWeb:\n        forceDateProvider:\n            allowedFormats:\n                - 'Y-m-d'\n                - 'Y-m-d H:i:s'\n                - 'Y-m-d\\TH:i:s'\n                - 'Y-m-d\\TH:i:sP'\n                - 'U'\n```\n\n#### Handle-bus traits (requires `coala/messenger-bundle`)\n\n```neon\nparameters:\n    iwfWeb:\n        handleBusTrait:\n            handleBusTraitMappings:\n                queryBus: 'Coala\\MessengerBundle\\Messenger\\HandleQueryBusTrait'\n            handleBusTraitNamespaces:\n                - 'App\\Controller'\n```\n\n#### Require invalid-data-test group (requires `coala/testing-bundle`)\n\n```neon\nparameters:\n    iwfWeb:\n        requireInvalidDataTestGroup:\n            requireInvalidDataTestGroupNamespaces:\n                - 'App\\Tests'\n```\n\n---\n\n## Rules\n\n### Common\n\n#### `iwfWeb.mbFunctionUsageRule` — Multibyte function usage\n\nFlags calls to string functions that have a multibyte-safe counterpart and may produce incorrect results when the input contains multibyte characters (e.g. UTF-8).\n\nAffected functions: `chr`, `ord`, `parse_str`, `str_pad`, `str_split`, `stripos`, `stristr`, `strlen`, `strpos`, `strrchr`, `strripos`, `strrpos`, `strstr`, `strtolower`, `strtoupper`, `substr`, `substr_count`.\n\n```php\n// ❌ flagged\n$len = strlen($userInput);\n\n// ✅ correct\n$len = mb_strlen($userInput);\n```\n\n---\n\n#### `iwfWeb.noAnnotationAsAttribute` — No legacy Symfony annotation namespaces\n\nPrevents using classes from the legacy `Symfony\\...\\Annotation\\` namespace as PHP 8 attributes. Symfony has migrated all annotations to `Symfony\\...\\Attribute\\`.\n\n```php\n// ❌ flagged\n#[Symfony\\Component\\Routing\\Annotation\\Route('/foo')]\n\n// ✅ correct\n#[Symfony\\Component\\Routing\\Attribute\\Route('/foo')]\n```\n\n---\n\n#### `iwfWeb.requiredUseAlias` — Required import aliases\n\nEnforces that configured namespaces are always imported under a specific alias. Applies to both regular `use` statements and group `use` statements.\n\n```php\n// ❌ flagged — missing alias\nuse Doctrine\\ORM\\Mapping;\n\n// ✅ correct\nuse Doctrine\\ORM\\Mapping as ORM;\n```\n\n---\n\n#### `iwfWeb.attributeRequirements` — Attribute companion requirements\n\nEnsures that when a trigger attribute is present on a method, all configured companion attributes are also present.\n\n```php\n// ❌ flagged — #[Route] without #[IsGranted]\n#[Route('/admin/users')]\npublic function list(): object { ... }\n\n// ✅ correct\n#[Route('/admin/users')]\n#[IsGranted('ROLE_ADMIN')]\npublic function list(): object { ... }\n```\n\n---\n\n### Controller\n\n#### `iwfWeb.controllerHandleReturnType` — Controller handle() return type\n\nIn controllers that use Symfony's `HandleTrait`, actions returning `$this-\u003ehandle(...)` must declare their return type as `object` (or `mixed`). A more specific type causes a `TypeError` when the message bus returns an unexpected response such as an `ErrorResponse`.\n\n```php\n// ❌ flagged — too specific, will TypeError on error responses\npublic function __invoke(Request $request): RecordsResponse\n{\n    return $this-\u003ehandle(new GetRecordsQuery());\n}\n\n// ✅ correct\npublic function __invoke(Request $request): object\n{\n    return $this-\u003ehandle(new GetRecordsQuery());\n}\n```\n\n---\n\n#### `iwfWeb.controllerMissingIsGranted` — Controller missing #[IsGranted]\n\nEvery public controller method carrying a `#[Route]` attribute must also carry a `#[IsGranted]` attribute — either on the method itself or on the class. Excludes abstract classes and any configured namespaces or class names.\n\n```php\n// ❌ flagged\n#[Route('/api/users')]\npublic function index(): object { ... }\n\n// ✅ correct\n#[Route('/api/users')]\n#[IsGranted('ROLE_USER')]\npublic function index(): object { ... }\n```\n\n---\n\n### Coala — DateProvider\n\n\u003e These rules are only active when `Coala\\DateProviderBundle` is present in the project.\n\n#### `iwfWeb.forceDateProviderNew` / `iwfWeb.forceDateProviderFuncCall` / `iwfWeb.forceDateProviderStaticCall`\n\nDisallows creating `DateTime`/`DateTimeImmutable` without an absolute date string argument, calling time-sensitive functions (`time()`, `date()`, etc.), or using static factory methods that produce the current time. Enforces the use of `DateProviderInterface` instead, which enables deterministic time in tests.\n\n```php\n// ❌ flagged\n$now = new DateTimeImmutable();\n$ts  = time();\n\n// ✅ correct\n$now = $this-\u003edateProvider-\u003enow();\n```\n\n---\n\n### Coala — Messenger\n\n\u003e This rule is only active when `Coala\\MessengerBundle` is present in the project.\n\n#### `iwfWeb.useHandleBusTrait`\n\nIn configured namespaces, if a class defines a setter method that corresponds to a configured handle-bus trait (e.g. `setQueryBus()`), it must use the matching trait instead of defining the setter manually.\n\n---\n\n### Coala — Testing\n\n\u003e This rule is only active when `Coala\\TestingBundle` is present in the project.\n\n#### `iwfWeb.requireInvalidDataTestGroup`\n\nTest methods that call `assertFailingValidation()` must carry `#[Group('invalid-data-test')]`. This allows the test suite to run invalid-data tests in isolation.\n\n```php\n// ❌ flagged\npublic function testInvalidEmail(): void\n{\n    $this-\u003eassertFailingValidation(...);\n}\n\n// ✅ correct\n#[Group('invalid-data-test')]\npublic function testInvalidEmail(): void\n{\n    $this-\u003eassertFailingValidation(...);\n}\n```\n\n---\n\n## Development\n\n### Prerequisites\n\n- Docker with Compose\n\n### Bootstrap\n\nAfter cloning the repository, run the install script to set up the vendor directory and extract PHPStan source files for IDE indexing:\n\n```bash\nbin/install.sh\n```\n\nThis is equivalent to running `composer install` — the PHPStan extraction is triggered automatically as a post-install hook and requires no additional IDE configuration.\n\n### Running tests\n\n```bash\nbin/test.sh\n```\n\nRuns PHPStan and PHPUnit against all configured Docker services sequentially.\n\nTo target a specific PHP version:\n\n```bash\nbin/test.sh 8.3\n```\n\n### Linting\n\n```bash\nbin/lint.sh\n```\n\nRuns PHP CS Fixer and applies fixes in place. To check without modifying files (as CI does), run:\n\n```bash\ncomposer lint:check\n```\n\n### Running Composer commands\n\n```bash\nbin/composer.sh \u003cargs\u003e\n```\n\nRuns Composer inside the default Docker container. Examples:\n\n```bash\nbin/composer.sh install\nbin/composer.sh require --dev some/package\n```\n\n### Debugging with Xdebug\n\nXdebug is included in the local Docker images and configured with `start_with_request=trigger`. To activate it, set the `XDEBUG_TRIGGER` environment variable:\n\n```bash\nXDEBUG_TRIGGER=1 bin/test.sh\n```\n\nOr configure your IDE to listen on port `9003` and set `XDEBUG_TRIGGER=1` in the Docker run environment.\n\n---\n\n## Contributing\n\nPlease read [CONTRIBUTING.md][contributing] for details on our code of conduct and the process for submitting pull requests.\n\nThis project uses [Conventional Commits](https://www.conventionalcommits.org/) for automated releases and changelog generation.\n\n## Versioning\n\nWe use [SemVer](http://semver.org/) for versioning. For available versions, see the [tags on this repository][gh-tags].\n\n## Authors\n\n### Special thanks for all the people who had helped this project so far\n\n- **Oliver** - [Oliver-Zieschang](https://github.com/Oliver-Zieschang)\n\nSee also the full list of [contributors][gh-contributors] who participated in this project.\n\n### I would like to join this list. How can I help the project?\n\nWe're currently looking for contributions for the following:\n\n- [ ] Bug fixes\n- [ ] Translations\n- [ ] etc...\n\nFor more information, please refer to our [CONTRIBUTING.md][contributing] guide.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE.txt](LICENSE.txt) file for details.\n\n## Acknowledgments\n\nThis project currently uses no third-party libraries or copied code.\n\n[license]: https://github.com/iwf-web/phpstan-rules/blob/main/LICENSE.txt\n[packagist]: https://packagist.org/packages/iwf-web/phpstan-rules\n[gh-tags]: https://github.com/iwf-web/phpstan-rules/tags\n[gh-contributors]: https://github.com/iwf-web/phpstan-rules/contributors\n[contributing]: https://github.com/iwf-web/.github/blob/main/CONTRIBUTING.md\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiwf-web%2Fphpstan-rules","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fiwf-web%2Fphpstan-rules","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiwf-web%2Fphpstan-rules/lists"}