# Symfony Plugin Premium

**Premium** features are paid Symfony Support features for PhpStorm and IntelliJ IDEA.

---

## Full Line Completion: Complete and inject service classes via property

**Feature ID:** `IncompletePropertyServiceInjectionContributor`  
**Date:** 2024-04-07  
**Feature Page:** [Full Line Completion: Complete and inject service classes via property](https://espend.de/phpstorm/plugin/symfony#incomplete-property-service-injection-contributor)  

Completes an unresolved controller or service property and inserts the matching constructor dependency so the property is backed by a real Symfony service.

This premium completion uses indexed autowireable services and keeps the generated property, constructor argument, and method-call completion together.

### Code Examples

```php
# Before completion:
final class ProductController
{
    public function index(): Response
    {
        $products = $this->productRepository->findAll();
    }
}
```

```php
# After applying the suggestion:
final class ProductController
{
    public function __construct(
        private readonly ProductRepository $productRepository,
    ) {
    }

    public function index(): Response
    {
        $products = $this->productRepository->findAll();
    }
}
```

---

## Full Line Completion: Doctrine QueryBuilder

**Feature ID:** `IncompleteQueryBuilderJoinContributor`  
**Date:** 2024-04-14  
**Feature Page:** [Full Line Completion: Doctrine QueryBuilder](https://espend.de/phpstorm/plugin/symfony#incomplete-query-builder-join-contributor)  

Completes Doctrine QueryBuilder joins and parameter bindings from the current query chain, including known aliases, relations, and unresolved DQL parameters.

The premium completion proposes whole method calls such as `join(...)` or `setParameter(...)` instead of only method names.

### Code Examples

```php
# Join completion:
$qb = $this->createQueryBuilder(alias: 'bike');
$qb->join('bike.category', 'category');
```

```php
# Parameter completion:
$qb->andWhere('bike.id = :bikeId');
$qb->setParameter('bikeId', $bikeId);
```

---

## Deprecated Doctrine Table attribute arguments

**Feature ID:** `DoctrineTableAttributeDeprecatedPropertiesInspection`  
**Date:** 2026-05-04  
**Feature Page:** [Deprecated Doctrine Table attribute arguments](https://espend.de/phpstorm/plugin/symfony#doctrine-table-attribute-deprecated-properties-inspection)  

Reports Doctrine ORM `#[ORM\Table]` attributes that still pass `indexes` or `uniqueConstraints`. Doctrine ORM deprecates these arguments because they no longer have an effect and will be removed in ORM 4.0.

Use standalone `#[ORM\Index]` and `#[ORM\UniqueConstraint]` attributes instead.

### Code Examples

```php
# Deprecated Table arguments:
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ORM\Table(indexes: [
    new ORM\Index(name: 'idx_product_sku', columns: ['sku']),
])]
class Product
{
}
```

```php
# Use dedicated attributes:
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ORM\Index(name: 'idx_product_sku', columns: ['sku'])]
class Product
{
}
```

---

## Bundle registerCommands() is deprecated

**Feature ID:** `RegisterCommandsDeprecationInspection`  
**Date:** 2026-06-02  
**Feature Page:** [Bundle registerCommands() is deprecated](https://espend.de/phpstorm/plugin/symfony#register-commands-deprecation-inspection)  

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.

### Code Examples

```php
# 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());
    }
}
```

```php
# 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
{
}
```

---

## Doctrine join column nullable is ignored

**Feature ID:** `DoctrineJoinColumnNullableDeprecationInspection`  
**Date:** 2026-06-03  
**Feature Page:** [Doctrine join column nullable is ignored](https://espend.de/phpstorm/plugin/symfony#doctrine-join-column-nullable-deprecation-inspection)  

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.

### Code Examples

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

```php
# Remove the ignored nullable flag:
#[ORM\ManyToMany(targetEntity: Group::class)]
#[ORM\JoinTable(joinColumns: [
    new ORM\JoinColumn(name: 'user_id'),
])]
private Collection $groups;
```

```xml
# XML mapping is covered too:
<join-column name="group_id" referenced-column-name="id" nullable="false" />
```

---

## Doctrine mapping ArrayAccess is deprecated

**Feature ID:** `DoctrineMappingArrayAccessDeprecationInspection`  
**Date:** 2026-06-02  
**Feature Page:** [Doctrine mapping ArrayAccess is deprecated](https://espend.de/phpstorm/plugin/symfony#doctrine-mapping-array-access-deprecation-inspection)  

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.

### Code Examples

```php
# Deprecated mapping array access:
$metadata = $entityManager->getClassMetadata(Entity::class);
$fieldMapping = $metadata->getFieldMapping('fieldName');
$length = $fieldMapping['length'] ?? null;
```

```php
# Use property access:
$metadata = $entityManager->getClassMetadata(Entity::class);
$fieldMapping = $metadata->getFieldMapping('fieldName');
$length = $fieldMapping->length ?? null;
```

---

## Doctrine current date/time string defaults are deprecated

**Feature ID:** `DoctrineCurrentDateTimeDefaultExpressionInspection`  
**Date:** 2026-06-02  
**Feature Page:** [Doctrine current date/time string defaults are deprecated](https://espend.de/phpstorm/plugin/symfony#doctrine-current-date-time-default-expression-inspection)  

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.

### Code Examples

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

```php
# 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

**Feature ID:** `DoctrineDiscriminatorMapDuplicateClassInspection`  
**Date:** 2026-06-02  
**Feature Page:** [Doctrine discriminator map duplicate classes](https://espend.de/phpstorm/plugin/symfony#doctrine-discriminator-map-duplicate-class-inspection)  

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.

### Code Examples

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

```php
# Keep one discriminator value per class:
#[ORM\DiscriminatorMap([
    'user' => User::class,
])]
abstract class BaseUser
{
}
```

---

## Doctrine Criteria ordering API deprecations

**Feature ID:** `DoctrineCollectionsCriteriaOrderingDeprecationInspection`  
**Date:** 2026-06-02  
**Feature Page:** [Doctrine Criteria ordering API deprecations](https://espend.de/phpstorm/plugin/symfony#doctrine-collections-criteria-ordering-deprecation-inspection)  

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.

### Code Examples

```php
# Deprecated Criteria calls:
$criteria->getOrderings();
$criteria->orderBy(['name' => 'ASC']);
$criteria->setFirstResult(null);
new Criteria($expr, [], null);
```

```php
# Use the newer API:
use Doctrine\Common\Collections\Order;

$criteria->orderings();
$criteria->orderBy(['name' => Order::Ascending]);
$criteria->setFirstResult(0);
new Criteria($expr, [], 0);
```

---

