PHPackages                             kocal/phpstan-symfony-ux - 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. kocal/phpstan-symfony-ux

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

kocal/phpstan-symfony-ux
========================

PHPStan rules for Symfony UX

v1.3.0(2mo ago)2825.2k—6.8%11MITPHPPHP &gt;=8.2CI passing

Since Nov 24Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/Kocal/phpstan-symfony-ux)[ Packagist](https://packagist.org/packages/kocal/phpstan-symfony-ux)[ RSS](/packages/kocal-phpstan-symfony-ux/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (5)Dependencies (10)Versions (7)Used By (1)

PHPStan for Symfony UX
======================

[](#phpstan-for-symfony-ux)

[![Packagist License](https://camo.githubusercontent.com/612203910ae6b4e1a78366e5b8eefc1523146b8bf318c095906a7eaff6e19c27/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6b6f63616c2f7068707374616e2d73796d666f6e792d7578)](https://camo.githubusercontent.com/612203910ae6b4e1a78366e5b8eefc1523146b8bf318c095906a7eaff6e19c27/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6b6f63616c2f7068707374616e2d73796d666f6e792d7578)[![Packagist Version](https://camo.githubusercontent.com/eadc1f4d4751f0804cea0c7f249640901fb14ad3ccdfe918dc3d7a6322227ec2/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6b6f63616c2f7068707374616e2d73796d666f6e792d7578)](https://packagist.org/packages/kocal/phpstan-symfony-ux)[![CI](https://github.com/Kocal/phpstan-symfony-ux/actions/workflows/ci.yaml/badge.svg)](https://github.com/Kocal/phpstan-symfony-ux/actions/workflows/ci.yaml)

A set of PHPStan rules to improve static analysis for [Symfony UX](https://github.com/symfony/ux) applications.

Installation
------------

[](#installation)

To install the PHPStan rules for Symfony UX, you can use Composer:

```
composer require --dev kocal/phpstan-symfony-ux
```

If you have [phpstan/extension-installer](https://github.com/phpstan/extension-installer) installed (which is the case by default), the extension will be automatically registered and you're ready to go.

If you don't use the extension installer, you'll need to manually add the extension to your `phpstan.neon` or `phpstan.dist.neon` configuration file:

```
includes:
    - vendor/kocal/phpstan-symfony-ux/extension.neon
```

Configuration
-------------

[](#configuration)

Each rule can be enabled individually by adding it to your `phpstan.neon` or `phpstan.dist.neon` configuration file.

If you prefer to includes all rules at once, you can include `rules.neon` instead:

```
includes:
    - vendor/kocal/phpstan-symfony-ux/rules.neon
```

LiveComponent Rules
-------------------

[](#livecomponent-rules)

### LiveActionMethodsVisibilityRule

[](#liveactionmethodsvisibilityrule)

Enforces that all methods annotated with `#[LiveAction]` in LiveComponents must be declared as public. LiveAction methods need to be publicly accessible to be invoked as component actions from the frontend.

```
rules:
    - Kocal\PHPStanSymfonyUX\Rules\LiveComponent\LiveActionMethodsVisibilityRule
```

> **Note:** The rule `LiveActionMethodsShouldBePublicRule` is deprecated and will be removed in version 2.0. Use `LiveActionMethodsVisibilityRule` instead.

```
// src/Twig/Components/TodoList.php
namespace App\Twig\Components;

use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;

#[AsLiveComponent]
final class TodoList
{
    #[LiveAction]
    private function addItem(): void
    {
    }
}
```

```
// src/Twig/Components/TodoList.php
namespace App\Twig\Components;

use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;

#[AsLiveComponent]
final class TodoList
{
    #[LiveAction]
    protected function deleteItem(): void
    {
    }
}
```

❌

```
// src/Twig/Components/TodoList.php
namespace App\Twig\Components;

use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;

#[AsLiveComponent]
final class TodoList
{
    #[LiveAction]
    public function addItem(): void
    {
    }

    #[LiveAction]
    public function deleteItem(): void
    {
    }
}
```

👍

### LiveListenerMethodsVisibilityRule

[](#livelistenermethodsvisibilityrule)

Enforces that all methods annotated with `#[LiveListener]` in LiveComponents must be declared as public. LiveListener methods need to be publicly accessible to be invoked when listening to events from the frontend.

```
rules:
    - Kocal\PHPStanSymfonyUX\Rules\LiveComponent\LiveListenerMethodsVisibilityRule
```

> **Note:** The rule `LiveListenerMethodsShouldBePublicRule` is deprecated and will be removed in version 2.0. Use `LiveListenerMethodsVisibilityRule` instead.

```
// src/Twig/Components/Notification.php
namespace App\Twig\Components;

use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveListener;

#[AsLiveComponent]
final class Notification
{
    #[LiveListener('notification:received')]
    private function onNotificationReceived(): void
    {
    }

    #[LiveListener('notification:dismissed')]
    protected function onNotificationDismissed(): void
    {
    }
}
```

❌

```
// src/Twig/Components/Notification.php
namespace App\Twig\Components;

use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveListener;

#[AsLiveComponent]
final class Notification
{
    #[LiveListener('notification:received')]
    public function onNotificationReceived(): void
    {
    }

    #[LiveListener('notification:dismissed')]
    public function onNotificationDismissed(): void
    {
    }
}
```

👍

### LivePropHydrationMethodsRule

[](#liveprophydrationmethodsrule)

Enforces that when a `#[LiveProp]` attribute specifies `hydrateWith` and `dehydrateWith` parameters:

- Both parameters must be specified together
- Both methods must exist in the component class and be declared as public
- The types must be compatible throughout the hydration/dehydration cycle:
    - The property must have a type declaration
    - The hydrate method must return the same type as the property
    - The dehydrate method must accept the same type as the property as its first parameter
    - The dehydrate method's return type must match the hydrate method's parameter type

This ensures data flows correctly between frontend and backend representations.

```
rules:
    - Kocal\PHPStanSymfonyUX\Rules\LiveComponent\LivePropHydrationMethodsRule
```

```
// src/Twig/Components/ProductList.php
namespace App\Twig\Components;

use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveProp;

#[AsLiveComponent]
final class ProductList
{
    // Error: Missing dehydrateWith parameter
    #[LiveProp(hydrateWith: 'hydrateFilters')]
    public array $filters;
}
```

```
// src/Twig/Components/ProductList.php
namespace App\Twig\Components;

use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveProp;

#[AsLiveComponent]
final class ProductList
{
    #[LiveProp(hydrateWith: 'hydrateFilters', dehydrateWith: 'dehydrateFilters')]
    public array $filters;

    // Error: Methods are private/protected instead of public
    private function hydrateFilters(array $data): array
    {
        return $data;
    }

    protected function dehydrateFilters(array $data): array
    {
        return $data;
    }
}
```

```
// src/Twig/Components/ShoppingCart.php
namespace App\Twig\Components;

use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveProp;

class Product
{
    public function __construct(public string $name, public float $price) {}
}

#[AsLiveComponent]
final class ShoppingCart
{
    #[LiveProp(hydrateWith: 'hydrateProduct', dehydrateWith: 'dehydrateProduct')]
    public Product $product;

    // Error: Return type doesn't match property type
    public function hydrateProduct(array $data): array
    {
        return $data;
    }

    // Error: Parameter type doesn't match property type
    public function dehydrateProduct(string $product): array
    {
        return [];
    }
}
```

❌

```
// src/Twig/Components/ShoppingCart.php
namespace App\Twig\Components;

use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveProp;

class Product
{
    public function __construct(public string $name, public float $price) {}
}

#[AsLiveComponent]
final class ShoppingCart
{
    #[LiveProp(hydrateWith: 'hydrateProduct', dehydrateWith: 'dehydrateProduct')]
    public Product $product;

    public function hydrateProduct(array $data): Product
    {
        return new Product($data['name'], $data['price']);
    }

    public function dehydrateProduct(Product $product): array
    {
        return ['name' => $product->name, 'price' => $product->price];
    }
}
```

👍

### LivePropModifierMethodRule

[](#livepropmodifiermethodrule)

Enforces that when a `#[LiveProp]` attribute specifies a `modifier` parameter:

- The method must exist in the component class and be declared as public
- The method must have 1 or 2 parameters:
    - First parameter: must be of type `LiveProp`
    - Second parameter (optional): must be of type `string`
- The method must return a `LiveProp` instance

This ensures that property modifiers are correctly implemented and can safely transform LiveProp configurations at runtime.

```
rules:
    - Kocal\PHPStanSymfonyUX\Rules\LiveComponent\LivePropModifierMethodRule
```

```
// src/Twig/Components/SearchComponent.php
namespace App\Twig\Components;

use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveProp;

#[AsLiveComponent]
final class SearchComponent
{
    #[LiveProp(modifier: 'modifyQueryProp')]
    public string $query;

    // Error: Method is not public
    private function modifyQueryProp(LiveProp $liveProp): LiveProp
    {
        return $liveProp;
    }

    // Error: Wrong return type
    public function modifyOtherProp(LiveProp $liveProp): string
    {
        return 'test';
    }

    // Error: Wrong first parameter type
    public function modifyAnotherProp(string $value): LiveProp
    {
        return new LiveProp();
    }
}
```

❌

```
// src/Twig/Components/SearchComponent.php
namespace App\Twig\Components;

use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\Mapping\UrlMapping;

#[AsLiveComponent]
final class SearchComponent
{
    #[LiveProp(modifier: 'modifyQueryProp')]
    public string $query;

    #[LiveProp]
    public ?string $alias = null;

    // Valid: with two parameters
    public function modifyQueryProp(LiveProp $liveProp, string $name): LiveProp
    {
        if ($this->alias) {
            $liveProp = $liveProp->withUrl(new UrlMapping(as: $this->alias));
        }
        return $liveProp;
    }

    // Valid: with one parameter
    public function modifyOtherProp(LiveProp $liveProp): LiveProp
    {
        return $liveProp->writable();
    }
}
```

👍

TwigComponent Rules
-------------------

[](#twigcomponent-rules)

Note

All these rules also apply to LiveComponents (classes annotated with `#[AsLiveComponent]`).

### ClassMustBeFinalRule

[](#classmustbefinalrule)

Enforces that all Twig Component classes must be declared as `final`. This prevents inheritance and promotes composition via traits, ensuring better code maintainability and avoiding tight coupling between components.

```
rules:
    - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\ClassMustBeFinalRule
```

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
class Alert
{
    public string $message;
}
```

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
abstract class Alert
{
    public string $message;
}
```

❌

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class Alert
{
    public string $message;
}
```

👍

### ClassNameMustNotEndWithComponentRule

[](#classnamemustnotendwithcomponentrule)

Forbid Twig Component class names from ending with "Component" suffix, as it creates redundancy since the class is already identified as a component through the `#[AsTwigComponent]` attribute.

```
rules:
    - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\ClassNameMustNotEndWithComponentRule
```

> **Note:** The rule `ClassNameShouldNotEndWithComponentRule` is deprecated and will be removed in version 2.0. Use `ClassNameMustNotEndWithComponentRule` instead.

```
// src/Twig/Components/AlertComponent.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class AlertComponent
{
}
```

❌

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class Alert
{
}
```

👍

### ExposePublicPropsMustBeFalseRule

[](#exposepublicpropsmustbefalserule)

Enforces that the `#[AsTwigComponent]` attribute has its `exposePublicProps` parameter explicitly set to `false`. This prevents public properties from being automatically exposed to templates, promoting explicit control over what data is accessible in your Twig components.

```
rules:
    - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\ExposePublicPropsMustBeFalseRule
```

> **Note:** The rule `ExposePublicPropsShouldBeFalseRule` is deprecated and will be removed in version 2.0. Use `ExposePublicPropsMustBeFalseRule` instead.

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class Alert
{
    public string $message;
}
```

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent(exposePublicProps: true)]
final class Alert
{
    public string $message;
}
```

❌

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent(exposePublicProps: false)]
final class Alert
{
    public string $message;
}
```

👍

### ForbiddenAttributesPropertyRule

[](#forbiddenattributespropertyrule)

Forbid the use of the `$attributes` property in Twig Components, which can lead to confusion when using `{{ attributes }}` (an instance of `ComponentAttributes` that is automatically injected) in Twig templates.

```
rules:
    - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\ForbiddenAttributesPropertyRule
```

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class Alert
{
    public $attributes;
}
```

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent(attributesVar: 'customAttributes')]
final class Alert
{
    public $customAttributes;
}
```

❌

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class Alert
{
}
```

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class Alert
{
    public $customAttributes;
}
```

👍

### ForbiddenClassPropertyRule

[](#forbiddenclasspropertyrule)

Forbid the use of the `$class` property in Twig Components, as it is considered a bad practice to manipulate CSS classes directly in components. Use `{{ attributes }}` or `{{ attributes.defaults({ class: '...' }) }}` in your Twig templates instead.

```
rules:
    - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\ForbiddenClassPropertyRule
```

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class Alert
{
    public $class;
}
```

❌

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class Alert
{
}
```

👍

### ForbiddenReadonlyRule

[](#forbiddenreadonlyrule)

Forbid the use of `readonly` on Twig Component classes and properties, except for constructor-promoted properties (injected services).

Using `readonly` on component classes or properties prevents the TwigComponent system from setting prop values after instantiation. Services injected via the constructor can be `readonly` since they are assigned at instantiation time.

Learn more at

```
rules:
    - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\ForbiddenReadonlyRule
```

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final readonly class Alert
{
    public string $message;
}
```

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class Alert
{
    public readonly string $message;
}
```

❌

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Psr\Log\LoggerInterface;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class Alert
{
    public string $message;

    public function __construct(
        private readonly LoggerInterface $logger,
    ) {
    }
}
```

👍

### MethodsVisibilityRule

[](#methodsvisibilityrule)

Enforces that all methods in Twig Components are either public or private, but not protected. Since Twig Components must be final classes and inheritance is forbidden (see `ForbiddenInheritanceRule`), protected methods serve no purpose and should be avoided.

**Exception:** Protected methods are allowed when they implement abstract methods defined in traits (e.g., `instantiateForm()` from `ComponentWithFormTrait`).

```
rules:
    - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\MethodsVisibilityRule
```

> **Note:** The rule `MethodsShouldBePublicOrPrivateRule` is deprecated and will be removed in version 2.0. Use `MethodsVisibilityRule` instead.

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class Alert
{
    public string $message;

    protected function formatMessage(): string
    {
        return strtoupper($this->message);
    }
}
```

❌

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class Alert
{
    public string $message;

    public function formatMessage(): string
    {
        return strtoupper($this->message);
    }

    private function helperMethod(): void
    {
        // ...
    }
}
```

👍

```
// src/Twig/Components/PostForm.php
namespace App\Twig\Components;

use Symfony\Component\Form\FormInterface;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\ComponentWithFormTrait;
use Symfony\UX\LiveComponent\DefaultActionTrait;

#[AsLiveComponent]
final class PostForm
{
    use DefaultActionTrait;
    use ComponentWithFormTrait;

    // Implementing abstract method from ComponentWithFormTrait is allowed
    protected function instantiateForm(): FormInterface
    {
        return $this->createForm(PostType::class);
    }
}
```

👍

### PostMountMethodSignatureRule

[](#postmountmethodsignaturerule)

Enforces that methods with the `#[PostMount]` attribute have the correct signature: they must be public with an optional parameter of type `array`, and a return type of `array`, `void`, or `array|void`. This ensures proper integration with the Symfony UX TwigComponent lifecycle hooks.

```
rules:
    - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\PostMountMethodSignatureRule
```

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use Symfony\UX\TwigComponent\Attribute\PostMount;

#[AsTwigComponent]
final class Alert
{
    #[PostMount]
    protected function postMount(): void
    {
    }
}
```

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use Symfony\UX\TwigComponent\Attribute\PostMount;

#[AsTwigComponent]
final class Alert
{
    #[PostMount]
    public function postMount(array $data): string
    {
        return 'invalid';
    }
}
```

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use Symfony\UX\TwigComponent\Attribute\PostMount;

#[AsTwigComponent]
final class Alert
{
    #[PostMount]
    public function postMount(string $data): void
    {
    }
}
```

❌

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use Symfony\UX\TwigComponent\Attribute\PostMount;

#[AsTwigComponent]
final class Alert
{
    #[PostMount]
    public function postMount(): void
    {
    }
}
```

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use Symfony\UX\TwigComponent\Attribute\PostMount;

#[AsTwigComponent]
final class Alert
{
    #[PostMount]
    public function postMount(array $data): array
    {
        return $data;
    }
}
```

👍

### PreMountMethodSignatureRule

[](#premountmethodsignaturerule)

Enforces that methods with the `#[PreMount]` attribute have the correct signature: they must be public and have exactly one parameter of type `array`, with a return type of `array`, `void`, or `array|void` . This ensures proper integration with the Symfony UX TwigComponent lifecycle hooks.

```
rules:
    - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\PreMountMethodSignatureRule
```

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use Symfony\UX\TwigComponent\Attribute\PreMount;

#[AsTwigComponent]
final class Alert
{
    #[PreMount]
    protected function preMount(array $data): array
    {
        return $data;
    }
}
```

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use Symfony\UX\TwigComponent\Attribute\PreMount;

#[AsTwigComponent]
final class Alert
{
    #[PreMount]
    public function preMount(string $data): array
    {
        return [];
    }
}
```

❌

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use Symfony\UX\TwigComponent\Attribute\PreMount;

#[AsTwigComponent]
final class Alert
{
    #[PreMount]
    public function preMount(array $data): array
    {
        $data['timestamp'] = time();

        return $data;
    }
}
```

👍

### PublicPropertiesMustBeCamelCaseRule

[](#publicpropertiesmustbecamelcaserule)

Enforces that all public properties in Twig Components follow camelCase naming convention. This ensures consistency and better integration with Twig templates where properties are passed and accessed using camelCase.

```
rules:
    - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\PublicPropertiesMustBeCamelCaseRule
```

> **Note:** The rule `PublicPropertiesShouldBeCamelCaseRule` is deprecated and will be removed in version 2.0. Use `PublicPropertiesMustBeCamelCaseRule` instead.

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class Alert
{
    public string $user_name;
    public bool $is_active;
}
```

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class Alert
{
    public string $UserName;
}
```

❌

```
// src/Twig/Components/Alert.php
namespace App\Twig\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final class Alert
{
    public string $userName;
    public bool $isActive;
}
```

👍

###  Health Score

50

—

FairBetter than 96% of packages

Maintenance84

Actively maintained with recent releases

Popularity39

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 98% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~23 days

Total

5

Last Release

82d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/193fce7c976005d2fdb59268f6ebc90f262d21e3cbc01e65300200ff70d74fe6?d=identicon)[Kocal](/maintainers/Kocal)

---

Top Contributors

[![Kocal](https://avatars.githubusercontent.com/u/2103975?v=4)](https://github.com/Kocal "Kocal (48 commits)")[![skmedix](https://avatars.githubusercontent.com/u/3246162?v=4)](https://github.com/skmedix "skmedix (1 commits)")

---

Tags

phpstanphpstan-rulessymfony-ux

###  Code Quality

TestsPHPUnit

Code StyleECS

### Embed Badge

![Health badge](/badges/kocal-phpstan-symfony-ux/health.svg)

```
[![Health](https://phpackages.com/badges/kocal-phpstan-symfony-ux/health.svg)](https://phpackages.com/packages/kocal-phpstan-symfony-ux)
```

###  Alternatives

[larastan/larastan

Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel

6.4k43.5M5.2k](/packages/larastan-larastan)[phpstan/phpstan-symfony

Symfony Framework extensions and rules for PHPStan

78268.9M1.5k](/packages/phpstan-phpstan-symfony)[phpstan/phpstan-doctrine

Doctrine extensions for PHPStan

66466.6M1.1k](/packages/phpstan-phpstan-doctrine)[phpat/phpat

PHP Architecture Tester

1.2k3.5M32](/packages/phpat-phpat)[spaze/phpstan-disallowed-calls

PHPStan rules to detect disallowed method &amp; function calls, constant, namespace, attribute, property &amp; superglobal usages, with powerful rules to re-allow a call or a usage in places where it should be allowed.

33120.0M375](/packages/spaze-phpstan-disallowed-calls)[mglaman/phpstan-drupal

Drupal extension and rules for PHPStan

20729.0M124](/packages/mglaman-phpstan-drupal)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
