Logo   espend.de
PHP Annotations

DocBlock annotation support, PHP attribute bridge features, Doctrine ORM helpers, inspections, and framework extension points for PhpStorm.

Links

GitHub

Issues & Source Code

JetBrains Marketplace

Features

Settings

Project settings for annotations and attributes
AnnotationSettings

Other Settings PHP Annotation

The plugin adds PHP > Annotations / Attributes settings for insert behavior and index maintenance.

The round-bracket option controls whether annotation and attribute completion inserts calls such as @Assert\NotBlank() and #[ORM\Entity()], or leaves the class name without brackets.

The same settings page exposes a reindex action for annotation metadata, useful after adding or updating vendor packages that provide new annotation classes.

With round brackets enabled:

/**
 * @Assert\NotBlank()
 */
private string $name;

With round brackets disabled:

/**
 * @Assert\NotBlank
 */
private string $name;
Configurable alias imports
UseAliasSettings

Other Settings Alias Import

Alias settings map a namespace to the alias that should be inserted during completion. This keeps common annotation code short while still creating real PHP imports.

Built-in aliases cover Symfony Validator, Doctrine ORM, JMS, Gedmo, VichUploader, FOSRest, Swagger/OpenAPI, OpenAPI Attributes, and Sunrise Router. Third-party plugins can add more defaults through the alias extension point.

Alias setting:

Doctrine\ORM\Mapping -> ORM
Symfony\Component\Validator\Constraints -> Assert
OpenApi\Attributes -> OA

Inserted code:

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity()]
#[ORM\Table(name: 'product')]
final class Product {}

Completion

Annotation class completion with target filtering
AnnotationClassCompletion

Completion PHP Docblock Annotation Alias

Completes annotation classes in PHP DocBlocks and filters suggestions by the current target, so class annotations, method annotations, property annotations, and nested annotations stay relevant.

Classes are discovered from the project index when they declare @Annotation. Their @Target declaration controls where they are suggested; annotations without an explicit target remain available as generic annotations.

Target-aware DocBlock completion:

/**
 * @Annotation
 * @Target("PROPERTY")
 */
final class Slug {}

final class Product
{
    /**
     * @<caret>
     */
    private string $slug;
}

Alias-aware insert result:

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 */
final class Product {}
Annotation property name completion
AnnotationPropertyCompletion

Completion PHP Docblock Property

Completes annotation property names from public annotation fields and Doctrine-style @Attributes metadata.

Virtual properties can be contributed by extension points, so frameworks can expose synthetic annotation arguments even when they are not real PHP fields.

Annotation class metadata:

/**
 * @Annotation
 * @Attributes({
 *     @Attribute("message", type="string"),
 *     @Attribute("groups", type="array")
 * })
 */
final class NotBlank {}

Completion usage:

/**
 * @NotBlank(<caret>)
 */
private string $name;
Typed property value completion
AnnotationPropertyValueCompletion

Completion PHP Docblock Attribute Enum

Completes values inside annotation and attribute arguments from the annotation class metadata.

Boolean fields offer true/false, @Enum declarations offer their allowed values, and array properties are handled separately so single-value suggestions do not leak into array-only contexts.

Annotation metadata:

/**
 * @Annotation
 */
final class GeneratedValue
{
    /**
     * @Enum({"AUTO", "SEQUENCE", "TABLE", "IDENTITY", "NONE", "UUID", "CUSTOM"})
     */
    public string $strategy = 'AUTO';

    public bool $enabled = true;
}

DocBlock and attribute completion:

/**
 * @ORM\GeneratedValue(strategy="<caret>")
 */
private int $id;

#[ORM\GeneratedValue(strategy: '<caret>')]
private int $id;
Nested annotation completion
NestedAnnotationCompletion

Completion PHP Docblock Nested

Supports completion inside nested annotation expressions, including nested arrays and whitespace variants in DocBlocks.

This is important for annotations that accept other annotations as structured configuration values.

Nested annotation values:

/**
 * @Security({
 *     @AccessControl(role="<caret>")
 * })
 */
public function edit(): Response
{
}

Nested completion scope:

/**
 * @Foo(foo={@Bar(<caret>)})
 */
final class Example {}
PHP attribute alias completion
AttributeAliasCompletion

Completion PHP Attribute Alias

Completes PHP attributes through the same alias configuration used for DocBlock annotations.

The completion uses existing use ... as ... imports and configured aliases, then verifies that the underlying class is a valid PHP attribute for the current declaration target.

Before completion:

final class Product
{
    #[<caret>]
    private string $name;
}

After selecting an alias item:

use Symfony\Component\Validator\Constraints as Assert;

final class Product
{
    #[Assert\NotBlank()]
    private string $name;
}
Class constant completion in DocBlocks
ClassConstantCompletion

Completion PHP Docblock Constant

Completes constants after :: inside annotation arguments and array arguments.

The same class-constant support also participates in navigation and import usage detection, so constants referenced from DocBlocks are treated as real class usages.

Constant completion:

use App\Routing\RouteName;

/**
 * @Route(name=RouteName::<caret>)
 */
public function show(): Response
{
}

Constant inside an array value:

/**
 * @SomeAnnotation(values={RouteName::ADMIN, RouteName::<caret>})
 */
final class Example {}
Symfony Route method completion
SymfonyRouteMethodsCompletion

Completion PHP Symfony Route Attribute

Completes HTTP methods for Symfony Route annotations and Route attributes when the caret is inside the methods array.

Supported targets are Symfony\Component\Routing\Annotation\Route and Symfony\Component\Routing\Attribute\Route.

Route annotation:

use Symfony\Component\Routing\Annotation\Route;

/**
 * @Route("/product", methods={"<caret>"})
 */
public function list(): Response
{
}

Route attribute:

use Symfony\Component\Routing\Attribute\Route;

#[Route('/product', methods: ['<caret>'])]
public function list(): Response
{
}
Navigate from annotations to classes and properties
AnnotationGoto

Navigation PHP Docblock Goto

Ctrl-click or Go to Declaration from a DocBlock annotation name opens the annotation class. Property names inside annotation arguments resolve to the backing PHP field or contributed virtual property target.

Class constants in DocBlocks resolve to their class or constant field, including namespace aliases and ::class references.

Navigation targets:

use App\Annotation\Audit;
use App\Routing\RouteName;

/**
 * @Audit(message="created", route=RouteName::PRODUCT_SHOW)
 */
final class Product {}

Supported jumps:

@Audit -> App\Annotation\Audit
message -> Audit::$message
RouteName -> App\Routing\RouteName
PRODUCT_SHOW -> RouteName::PRODUCT_SHOW
References from annotation and attribute values
AnnotationValueReferences

Navigation PHP Docblock Attribute Reference

Annotation value reference providers connect string values to framework-specific targets. The central bridge supports DocBlock default values, named DocBlock properties, attribute default values, and named attribute arguments.

Doctrine uses this for repository classes, entity fields, DBAL types, embeddables, and custom ID generator classes.

DocBlock reference:

/**
 * @ORM\Entity(repositoryClass="ProductRepository")
 */
final class Product {}

Attribute reference:

#[ORM\ManyToMany(targetEntity: Category::class, mappedBy: 'products')]
private Collection $categories;
Optimize Imports keeps annotation imports
OptimizeImportsBridge

Navigation PHP Docblock Imports

The plugin attaches real PSI references from annotation DocTags to imported classes and namespace aliases.

This prevents PhpStorm's Code > Optimize Imports action from removing imports that are only used inside DocBlocks.

DocBlock-only import usage:

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 */
final class Product {}

Class constants count as usage too:

use App\Routing\RouteName;

/**
 * @Route(name=RouteName::PRODUCT_SHOW)
 */
public function show(): Response
{
}

Linemarker

Annotation and attribute usage gutter markers
AnnotationUsageLineMarker

Linemarker PHP Docblock Attribute Gutter

Annotation classes and PHP attribute classes receive a gutter marker when the project contains indexed usages.

The marker opens a lazy usage target list, making it practical to jump from the annotation implementation to code that applies it.

Provider class:

/**
 * @Annotation
 */
final class Audit {}

Usage target:

/**
 * @Audit(event="product.created")
 */
final class Product {}

Inspections

Missing annotation import
AnnotationMissingUseInspection
Inspection PHP Docblock Quickfix

Reports DocBlock annotations that look like project annotation classes but are not imported or resolvable from the current namespace.

The quick fix imports the selected annotation class and preserves aliases when several candidates are possible.

Before quick fix:

/**
 * @NotBlank()
 */
private string $name;

After quick fix:

use Symfony\Component\Validator\Constraints\NotBlank;

/**
 * @NotBlank()
 */
private string $name;
Deprecated annotation classes
AnnotationDeprecatedInspection
Inspection PHP Docblock Deprecated

Highlights annotation usages whose underlying annotation class is deprecated.

Deprecated annotations are also deprioritized in completion, so active annotation classes appear before deprecated alternatives.

Deprecated annotation usage:

/**
 * @OldRoute("/legacy")
 */
public function legacy(): Response
{
}

Annotation class:

/**
 * @Annotation
 * @deprecated Use NewRoute instead.
 */
final class OldRoute {}
Class constant validation in DocBlocks
AnnotationDocBlockClassConstantInspections
Inspection PHP Docblock Constant

Checks class constant expressions inside DocBlock annotation values.

The plugin reports unresolved classes behind ::class and highlights deprecated class or constant usage inside annotation arguments.

Unresolved class constant:

/**
 * @Route(defaults={MissingController::class})
 */
public function index(): Response
{
}

Deprecated constant:

/**
 * @SomeAnnotation(mode=LegacyMode::OLD_VALUE)
 */
final class Example {}
Deprecated Doctrine column types
DoctrineTypeDeprecatedInspection
Inspection PHP Doctrine Attribute Deprecated

Reports deprecated Doctrine DBAL column type usages in ORM column annotations and attributes.

The inspection resolves custom DBAL type classes, Doctrine 3 Doctrine\DBAL\Types\Types constants, and built-in fallback types before checking deprecation metadata.

DocBlock mapping:

/**
 * @ORM\Column(type="json_array")
 */
private array $payload = [];

Attribute mapping:

#[ORM\Column(type: 'json_array')]
private array $payload = [];
Missing Doctrine repository class
RepositoryClassInspection
Inspection PHP Doctrine Quickfix

Reports Doctrine entity mappings whose repositoryClass value cannot be resolved.

The quick fix uses the same repository generation logic as the editor action, creating or wiring the repository class when possible.

Problematic mapping:

/**
 * @ORM\Entity(repositoryClass="ProductRepository")
 */
final class Product {}

Generated target:

namespace App\Repository;

use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;

final class ProductRepository extends ServiceEntityRepository
{
}

Doctrine

Doctrine mapping references
DoctrineMappingReferences

Navigation PHP Doctrine Docblock Attribute

Adds completion and navigation for common Doctrine ORM mapping values.

Supported mappings include repositoryClass, targetEntity, mappedBy, inversedBy, embedded class references, and custom ID generator classes.

DocBlock relation field completion:

/**
 * @ORM\ManyToMany(targetEntity="Category", inversedBy="<caret>")
 */
private Collection $categories;

Attribute relation field completion:

#[ORM\ManyToMany(targetEntity: Category::class, mappedBy: '<caret>')]
private Collection $categories;
Doctrine column type completion and navigation
DoctrineColumnTypes

Completion PHP Doctrine Dbal Type

Completes Doctrine DBAL type names in @ORM\Column(type=...) and resolves them back to their type classes.

The provider reads custom subclasses of Doctrine\DBAL\Types\Type, Doctrine 3 Doctrine\DBAL\Types\Types constants, and static fallback types.

Column type completion:

/**
 * @ORM\Column(type="<caret>")
 */
private array $payload = [];

Doctrine 3 type source:

final class Types
{
    public const JSON = 'json';
}
Doctrine column name suggestions
DoctrineColumnNameCompletion

Completion PHP Doctrine Attribute

Suggests snake_case column names from PHP property names for Doctrine Column, JoinColumn, and InverseJoinColumn mappings.

The attribute path also supports constructor promoted properties, so modern readonly entity style remains covered.

Property mapping:

/**
 * @ORM\Column(name="<caret>")
 */
private string $createdAt;

Promoted property mapping:

public function __construct(
    #[ORM\Column(name: '<caret>')]
    private readonly int $attributeId,
) {
}
Doctrine static value completion
DoctrineStaticValues

Completion PHP Doctrine Completion

Completes known Doctrine static string values where the valid set is small and mapping-specific.

For example, JoinColumn(onDelete=...) offers the supported delete actions without polluting array-value contexts.

DocBlock mapping:

/**
 * @ORM\JoinColumn(onDelete="<caret>")
 */
private ?Category $category = null;

Attribute mapping:

#[ORM\JoinColumn(onDelete: '<caret>')]
private ?Category $category = null;

Intentions

Add Doctrine column mapping
DoctrineColumnIntention
Intention PHP Doctrine Attribute Generate

Adds an ORM field mapping for an unmapped entity property.

The generator detects existing project style and writes either DocBlock annotations or PHP attributes. It guesses column type from the property name and PHP type, treats nullable types as nullable columns, and maps PHP arrays to JSON.

Before:

use Doctrine\ORM\Mapping as ORM;

final class Product
{
    private ?array $payload = null;
}

After:

use Doctrine\ORM\Mapping as ORM;

final class Product
{
    #[ORM\Column(type: 'json', nullable: true)]
    private ?array $payload = null;
}
Add Doctrine repository
DoctrineRepositoryIntention
Intention PHP Doctrine Repository Quickfix

Adds a repository class to an entity mapping or creates the repository file when it does not exist.

The action searches common repository namespaces, creates a Repository directory when possible, and uses the ServiceEntityRepository template when DoctrineBundle is available.

Before:

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 */
final class Product
{
}

After:

use App\Repository\ProductRepository;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass=ProductRepository::class)
 */
final class Product
{
}

Generator

Generate Doctrine entity and embeddable metadata
DoctrineOrmClassGenerator
Generator PHP Doctrine Generate

Adds Generate-menu actions for ORM class metadata and embeddable class metadata.

The class generator inserts the ORM alias, adds Entity and Table metadata, and includes a repository class reference when a matching repository already exists. The embedded-class generator writes Embeddable metadata.

Entity class output:

use Doctrine\ORM\Mapping as ORM;

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

Embeddable output:

use Doctrine\ORM\Mapping as ORM;

#[ORM\Embeddable]
final class Money
{
}
Repository file templates
DoctrineRepositoryTemplates
Generator PHP Doctrine Repository Template

Repository generation uses internal PhpStorm file templates instead of hard-coded file text.

Symfony projects with DoctrineBundle receive a ServiceEntityRepository-style repository; plain Doctrine projects receive a lightweight EntityRepository-style class.

Symfony-style repository:

namespace App\Repository;

use App\Entity\Product;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

final class ProductRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Product::class);
    }
}

Other

Indexed annotation metadata
AnnotationIndexAndTargets

Other PHP Index Performance

The plugin indexes annotation classes and annotation usages from PHP files, then reuses those indexes for completion, navigation, inspections, and usage markers.

Recent 12.x work optimized annotation and attribute lookup paths with index-backed caches and static PSI patterns, which matters in projects with large vendor directories.

Indexed annotation declaration:

/**
 * @Annotation
 * @Target("METHOD")
 */
final class RequiresPermission
{
    public string $value;
}

Target-aware usage:

/**
 * @RequiresPermission("product.update")
 */
public function update(): Response
{
}
DocBlock annotations and PHP attributes bridge
PhpAttributesBridge

Other PHP Attribute Bridge

The plugin treats PHP attributes as first-class peers of DocBlock annotations for many extension-driven features.

Default values, named arguments, array values, references, alias completion, and Doctrine mapping helpers reuse the same provider model so framework integrations can support both syntaxes consistently.

Same framework concept in both syntaxes:

use Symfony\Component\Validator\Constraints\NotBlank;

/**
 * @NotBlank(message="Name is required.")
 */
private string $legacyName;

#[NotBlank(message: 'Name is required.')]
private string $name;
Optional PHP Toolbox provider bridge
PhpToolboxIntegration

Other PHP Toolbox Optional

When PHP Toolbox is installed, this plugin exposes annotation signatures to Toolbox providers.

Toolbox JSON can target default annotation values, named annotation properties, and array properties through annotation and annotation_array signature types.

Default or named value provider:

{
  "registrar": [
    {
      "language": "php",
      "provider": "routes",
      "signatures": [
        {
          "class": "Symfony\\Component\\Routing\\Annotation\\Route",
          "field": "condition",
          "type": "annotation"
        }
      ]
    }
  ]
}

Array value provider:

{
  "class": "Symfony\\Component\\Routing\\Annotation\\Route",
  "field": "methods",
  "type": "annotation_array"
}
Extension points for framework plugins
ExtensionPoints

Other PHP Api Extension

The plugin exposes dynamic extension points so Symfony and other framework plugins can add annotation-specific behavior without modifying the core plugin.

Extension points cover completion, references, DocTag navigation, DocTag annotation highlighting, global namespaces, virtual properties, and default alias providers.

Available extension concepts:

<PhpAnnotationCompletionProvider implementation="Vendor\\CompletionProvider" />
<PhpAnnotationReferenceProvider implementation="Vendor\\ReferenceProvider" />
<PhpAnnotationDocTagGotoHandler implementation="Vendor\\GotoHandler" />
<PhpAnnotationVirtualProperties implementation="Vendor\\VirtualProperties" />
<PhpAnnotationUseAlias implementation="Vendor\\UseAliasProvider" />