Logo   espend.de
Symfony type icons for PHP classes
PhpClassFileIconProvider
2026-06-08

Other PHP UX Doctrine Form Console

Decorates PHP class files with Symfony-specific icons so controllers, entities, repositories, form types, and console commands are easier to distinguish in the project tree.

The icon decoration is configurable in the Symfony plugin settings and uses the same Symfony metadata that powers navigation and inspections.

Decorated PHP class types:

#[AsCommand(name: 'app:reindex-products')]
final class ReindexProductsCommand extends Command
{
}

#[ORM\Entity(repositoryClass: ProductRepository::class)]
final class Product
{
}

final class ProductType extends AbstractType
{
}

#[Route('/products')]
final class ProductController extends AbstractController
{
}
Doctrine join column nullable is ignored
DoctrineJoinColumnNullableDeprecationInspection
2026-06-03
Inspection PHP XML Yaml Doctrine Paid

Reports Doctrine ORM mapping metadata that explicitly sets nullable on join columns where Doctrine ORM 3.6 ignores the value and Doctrine ORM 4.0 rejects it.

The inspection covers many-to-many join columns and identifier to-one join columns in PHP attributes, XML mapping files, and YAML mapping files.

Deprecated PHP attribute metadata:

#[ORM\ManyToMany(targetEntity: Group::class)]
#[ORM\JoinTable(joinColumns: [
    new ORM\JoinColumn(name: 'user_id', nullable: true),
])]
private Collection $groups;

Remove the ignored nullable flag:

#[ORM\ManyToMany(targetEntity: Group::class)]
#[ORM\JoinTable(joinColumns: [
    new ORM\JoinColumn(name: 'user_id'),
])]
private Collection $groups;

XML mapping is covered too:

<join-column name="group_id" referenced-column-name="id" nullable="false" />
Doctrine Criteria ordering API deprecations
DoctrineCollectionsCriteriaOrderingDeprecationInspection
2026-06-02
Inspection PHP Doctrine Paid

Reports deprecated Doctrine Collections Criteria APIs around ordering and null offsets.

The inspection detects Criteria::getOrderings(), string order directions passed to orderBy(), and explicit null first-result offsets.

Deprecated Criteria calls:

$criteria->getOrderings();
$criteria->orderBy(['name' => 'ASC']);
$criteria->setFirstResult(null);
new Criteria($expr, [], null);

Use the newer API:

use Doctrine\Common\Collections\Order;

$criteria->orderings();
$criteria->orderBy(['name' => Order::Ascending]);
$criteria->setFirstResult(0);
new Criteria($expr, [], 0);
Doctrine current date/time string defaults are deprecated
DoctrineCurrentDateTimeDefaultExpressionInspection
2026-06-02
Inspection PHP XML Yaml Doctrine Paid

Reports Doctrine date, time, and timestamp field defaults that still use SQL strings such as CURRENT_TIMESTAMP.

Doctrine ORM 3.6 deprecates these string defaults for date/time fields; use DBAL DefaultExpression value objects instead. The inspection covers PHP attributes, XML, and YAML metadata when the matching vendor support is installed.

Deprecated string default:

#[ORM\Column(
    type: Types::DATETIME_IMMUTABLE,
    options: ['default' => 'CURRENT_TIMESTAMP'],
)]
private \DateTimeImmutable $createdAt;

Use a DBAL DefaultExpression:

use Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp;

#[ORM\Column(
    type: Types::DATETIME_IMMUTABLE,
    options: ['default' => new CurrentTimestamp()],
)]
private \DateTimeImmutable $createdAt;
Doctrine discriminator map duplicate classes
DoctrineDiscriminatorMapDuplicateClassInspection
2026-06-02
Inspection PHP XML Doctrine Paid

Reports discriminator maps where the same class is mapped to multiple discriminator values.

Doctrine ORM 3.4 deprecates duplicate class entries in a discriminator map, and Doctrine ORM 4.0 turns this into an error. The inspection covers PHP attributes, ClassMetadata::setDiscriminatorMap(), and XML mapping files.

Deprecated duplicate class mapping:

#[ORM\DiscriminatorMap([
    'user' => User::class,
    'legacy_user' => User::class,
])]
abstract class BaseUser
{
}

Keep one discriminator value per class:

#[ORM\DiscriminatorMap([
    'user' => User::class,
])]
abstract class BaseUser
{
}
Doctrine mapping ArrayAccess is deprecated
DoctrineMappingArrayAccessDeprecationInspection
2026-06-02
Inspection PHP Doctrine Paid

Reports deprecated array access on Doctrine ORM mapping value objects that use Doctrine\ORM\Mapping\ArrayAccessImplementation.

The quick fix rewrites safe array reads to public property access when Doctrine's vendor deprecation is available in the project.

Deprecated mapping array access:

$metadata = $entityManager->getClassMetadata(Entity::class);
$fieldMapping = $metadata->getFieldMapping('fieldName');
$length = $fieldMapping['length'] ?? null;

Use property access:

$metadata = $entityManager->getClassMetadata(Entity::class);
$fieldMapping = $metadata->getFieldMapping('fieldName');
$length = $fieldMapping->length ?? null;
Bundle registerCommands() is deprecated
RegisterCommandsDeprecationInspection
2026-06-02
Inspection PHP Paid

Reports application bundles that override the deprecated Symfony Bundle::registerCommands() hook when the installed vendor method is marked deprecated since Symfony 8.1.

Use #[AsCommand] on command classes or the console.command service tag instead.

Deprecated bundle hook:

use Symfony\Component\Console\Application;
use Symfony\Component\HttpKernel\Bundle\Bundle;

final class AppBundle extends Bundle
{
    public function registerCommands(Application $application): void
    {
        $application->add(new ReindexProductsCommand());
    }
}

Attribute-based command registration:

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;

#[AsCommand(name: 'app:reindex-products')]
final class ReindexProductsCommand extends Command
{
}
Complete Twig constant() references
TwigConstantEnumResolver
2026-05-28

Completion Twig Navigation Find Usages

Completes and resolves PHP constants in Twig constant() calls, including fully qualified class constants, namespaced global constants, and object-relative constants.

The same resolver is used by navigation and Find Usages, so constant references in Twig stay connected to their PHP declarations.

Class and namespaced constants:

{{ constant('App\\Enum\\Status::ACTIVE') }}
{{ constant('BugDemo\\NAMESPACED_CONST') }}

Object-relative constants:

{# @var suite \BugDemo\CardSuite #}
{{ constant('CLUBS', suite) }}
Navigation for typed and named default service bindings
YamlDefaultServiceBindingNavigation
2026-05-28

Navigation Yaml Service

Navigates from YAML _defaults.bind entries to the matching PHP type, parameter, or class target.

This covers both typed bindings and named argument bindings, so default wiring rules remain traceable in larger service files.

Typed and named bindings:

services:
  _defaults:
    bind:
      Psr\Log\LoggerInterface: '@monolog.logger'
      string $projectDir: '%kernel.project_dir%'
Controller action is deprecated
RouteControllerDeprecatedInspection
2026-05-26
Inspection PHP Twig Yaml XML Routing

Reports routes and route usages that point to controller actions marked as deprecated. This helps identify outdated routes that should be removed or updated.

The inspection covers YAML/XML route definitions, PHP route references, and Twig path()/url() calls.

// Controller with deprecated action:
class ProductController extends AbstractController
{
    #[Route('/old-product', name: 'app_old_product')]
    #[Deprecated('Use app_product_show instead')]
    public function oldAction(): Response
    {
        // ...
    }
}

Twig route usage:

{{ url('app_old_product') }}
{{ path('app_old_product') }}
Twig loop context type resolution
TwigLoopContextTypeResolution
2026-05-18

Type Twig

Resolves loop variables and the surrounding loop scope through included templates, so repeated row templates keep type-aware completion and inspections.

This also preserves parent context inheritance when a template is included from inside a for block.

Loop context inheritance:

{% for product in category.products %}
    {% include 'product/_row.html.twig' with { product: product } %}
{% endfor %}

{# product/_row.html.twig #}
{{ loop.index }} {{ product.name }}
Twig method-chain type resolution
TwigMethodChainTypeResolution
2026-05-18

Completion Twig Navigation

Improves Twig completion, navigation, and inspections across chained method calls, property shortcuts, function return types, and filter return types.

This enables suggestions on expressions like entry.children.entries, method-call chains, and values returned by Twig functions or filters.

For-loop path resolution:

{# @var root \App\Dto\CategoryTree #}
{% for entry in root.children.entries %}
    {{ entry.name }}
{% endfor %}

Function/filter return type chains:

{{ product_for_sku(sku).manufacturer.name }}
{{ order|latest_invoice.number }}
Twig include and embed context type resolution
TwigIncludeContextParser
2026-05-10

Type Twig Navigation

Resolves Twig template variables from include and embed context hashes so included templates receive the correct root variables for completion, navigation, and inspections.

Context handling supports explicit keys, inherited parent variables, only isolation, with_context: false, and array or ternary template targets.

Include and embed context keys:

{% include 'product/_card.html.twig' with {
    product: product,
    currentView: 'grid'
} only %}

{% embed 'product/_panel.html.twig' with { product: product } %}
    {% block body %}{{ product.name }}{% endblock %}
{% endembed %}
Include and embed context key completion
TwigIncludeEmbedContextKeyCompletion
2026-05-10

Completion Twig Navigation

Completes top-level variable names inside Twig include and embed context hashes from the target template.

The same context key can navigate back to the variable usage in the included template, so forwarded values stay connected to the template that expects them.

Included template variables:

{# product/_card.html.twig #}
{{ product.name }}
{{ currentView }}

Context key completion:

{% include 'product/_card.html.twig' with {
    product: product,
    currentView: 'grid'
} only %}

{% embed 'product/_card.html.twig' with { product: product } %}
    {% block body %}{{ product.name }}{% endblock %}
{% endembed %}