PHPackages                             edhrendal-sf-tools/phpstan-edhrendal - 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. edhrendal-sf-tools/phpstan-edhrendal

ActivePhpstan-extension[Testing &amp; Quality](/categories/testing)

edhrendal-sf-tools/phpstan-edhrendal
====================================

PHPStan custom rules for Edhrendal projects

0.2.1(2w ago)04MITPHPPHP &gt;=8.5

Since May 19Pushed 6d agoCompare

[ Source](https://github.com/EdhrendalSfTools/phpstan-edhrendal)[ Packagist](https://packagist.org/packages/edhrendal-sf-tools/phpstan-edhrendal)[ RSS](/packages/edhrendal-sf-tools-phpstan-edhrendal/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (3)Dependencies (3)Versions (4)Used By (0)

phpstan-edhrendal
=================

[](#phpstan-edhrendal)

PHPStan extension providing custom static analysis rules for Edhrendal projects.

Rules are **opt-in** — none are active by default. Include only the ones you need.

Requirements
------------

[](#requirements)

VersionPHP`>= 8.5``phpstan/phpstan``~2.1.0`Installation
------------

[](#installation)

> **Important — use a dedicated quality tools project**
>
> This package should **not** be installed as a dev dependency of your application. QA tools (PHPStan, PHP CS Fixer, etc.) belong in a separate Composer project, isolated from your application's dependency tree. This avoids version conflicts, keeps your application's `composer.lock` clean, and makes tool upgrades independent from application releases.
>
> A common convention is a `tools/` directory at the root of your repository with its own `composer.json`, or a dedicated repository shared across multiple projects.
>
> ```
> my-project/
> ├── tools/
> │   ├── composer.json   ← QA tools live here
> │   └── composer.lock
> ├── src/
> └── composer.json       ← application dependencies only
>
> ```

```
# From your QA tools project
composer require edhrendal-sf-tools/phpstan-edhrendal
```

Usage
-----

[](#usage)

`extension.neon` defines the full configuration schema and default values for all rules. How it gets loaded depends on your setup.

### Standard setup (PHPStan in the same vendor as the project)

[](#standard-setup-phpstan-in-the-same-vendor-as-the-project)

PHPStan auto-loads `extension.neon` via `extra.phpstan.includes` in `composer.json`. You do not need to include it manually — just include the rules you want:

```
# phpstan.neon
includes:
    - vendor/edhrendal-sf-tools/phpstan-edhrendal/rules/doctrine/no-repository-magic-method.neon
    - vendor/edhrendal-sf-tools/phpstan-edhrendal/rules/php/named-arguments.neon
    - vendor/edhrendal-sf-tools/phpstan-edhrendal/rules/symfony/controller-invokable.neon
```

### Separate tools directory

[](#separate-tools-directory)

When PHPStan is installed in a dedicated directory (e.g. `tools/`), its auto-discovery does not cover that vendor tree. You must include `extension.neon` explicitly, the same way you would for `phpstan-symfony` or `phpstan-doctrine`:

```
# phpstan.neon
includes:
    - /tools/phpstan/vendor/phpstan/phpstan-symfony/extension.neon
    - /tools/phpstan/vendor/phpstan/phpstan-doctrine/extension.neon
    - /tools/phpstan/vendor/edhrendal-sf-tools/phpstan-edhrendal/extension.neon
    - /tools/phpstan/vendor/edhrendal-sf-tools/phpstan-edhrendal/rules/doctrine/no-repository-magic-method.neon
    - /tools/phpstan/vendor/edhrendal-sf-tools/phpstan-edhrendal/rules/php/named-arguments.neon
    - /tools/phpstan/vendor/edhrendal-sf-tools/phpstan-edhrendal/rules/symfony/controller-invokable.neon
```

All parameters have sensible defaults. Override only what differs from the defaults:

```
# phpstan.neon
includes:
    - vendor/edhrendal-sf-tools/phpstan-edhrendal/rules/doctrine/no-repository-magic-method.neon
    - vendor/edhrendal-sf-tools/phpstan-edhrendal/rules/symfony/controller-invokable.neon

parameters:
    edhrendal:
        doctrine:
            repository:
                strict: true
        symfony:
            controller:
                rootAllowedDomains:
                    - index
                    - home
                    - dashboard
```

Available Rules
---------------

[](#available-rules)

---

### `NoRepositoryMagicMethodRule` — Doctrine

[](#norepositorymagicmethodrule--doctrine)

Forbids the use of generic and magic Doctrine repository methods in favor of explicit, named methods declared directly in the repository class.

**Always reported:**

CallReason`$repo->findBy(['field' => $value])`Generic criteria array — create a named method`$repo->findOneBy(['field' => $value])`Generic criteria array — create a named method`$repo->findByFoo(…)`Magic method via `__call`, not declared in the class`$repo->findOneByFoo(…)`Magic method via `__call`, not declared in the class**Also reported in strict mode:**

Call`$repo->find($id)``$repo->findAll()`**Include:**

```
# phpstan.neon
includes:
    - vendor/edhrendal-sf-tools/phpstan-edhrendal/rules/doctrine/no-repository-magic-method.neon
```

**Strict mode (optional):**

```
# phpstan.neon
includes:
    - vendor/edhrendal-sf-tools/phpstan-edhrendal/rules/doctrine/no-repository-magic-method.neon

parameters:
    edhrendal:
        doctrine:
            repository:
                strict: true  # default: false
```

**Example — before / after:**

```
// ❌ reported
$this->userRepository->findBy(['active' => true]);
$this->userRepository->findByEmail($email);

// ✅ ok
$this->userRepository->findActive();
$this->userRepository->findOneByEmail($email); // if declared in the class
```

---

### `ControllerInvokableRule` — Symfony

[](#controllerinvokablerule--symfony)

Enforces structural and naming conventions on Symfony controllers.

**Always reported:**

ViolationDescriptionBad namingClass name does not follow `{Domain}{HttpMethod}Controller` (e.g. `PeriodeCalculGetController`)Missing `__invoke()`Controller does not declare a `__invoke()` methodPublic non-magic methodController declares a public method other than magic ones (those starting with `__`)Root placementController sits directly under the `Controller` namespace segment without a sub-namespaceRecognised HTTP methods: `Get`, `Post`, `Put`, `Patch`, `Delete`, `Head`, `Options`, `Connect`, `Trace`, `Any`.

**Include:**

```
# phpstan.neon
includes:
    - vendor/edhrendal-sf-tools/phpstan-edhrendal/rules/symfony/controller-invokable.neon
```

**Parameters (optional):**

```
# phpstan.neon
includes:
    - vendor/edhrendal-sf-tools/phpstan-edhrendal/rules/symfony/controller-invokable.neon

parameters:
    edhrendal:
        symfony:
            controller:
                rootAllowedDomains:       # default: [index, home] — case-insensitive
                    - index
                    - home
                    - dashboard           # add any domain used for your index page
                excludedClassesFile: null # path to a PHP file returning string[] of FQCNs
```

The `excludedClassesFile` is a PHP file that returns an array of fully-qualified class names to skip entirely. Changes (additions, removals) are picked up on the next PHPStan run without recompilation:

```
// config/phpstan/excluded_controllers.php
