Links
Features
Inspections
2022-03-19
Reports when a Symfony Controller is injected as a dependency into another service. Controllers are designed to be invoked by the framework via routing, not used as dependencies in other services.
This inspection helps identify incorrect service injection patterns that may lead to architectural issues.
Avoid:
public function __construct(private ProductController $controller) {}
2022-03-19
Reports constructor parameters that reference classes which cannot be resolved to a valid service in the container. This typically occurs when:
- Using a concrete class instead of an interface (e.g.,
EntityManagerinstead ofEntityManagerInterface) - Referencing a class that is not registered as a service
- Using a deprecated or non-existent class name
Instead of:
public function __construct(private EntityManager $em) {}
Use the interface:
public function __construct(private EntityManagerInterface $em) {}
2025-12-03
Reports invokable Symfony Commands using #[AsCommand] attribute whose __invoke() method lacks an int return type. Since Symfony 7.3, commands should declare int as return type for the exit code (e.g., Command::SUCCESS, Command::FAILURE).
Instead of:
#[AsCommand(name: 'app:my-command')]
class MyCommand extends Command
{
public function __invoke()
{
return Command::SUCCESS;
}
}
Use:
#[AsCommand(name: 'app:my-command')]
class MyCommand extends Command
{
public function __invoke(): int
{
return Command::SUCCESS;
}
}
2025-12-03
Reports invokable Symfony Commands using #[AsCommand] attribute whose __invoke() method returns non-integer values. Since Symfony 7.3, commands must return an integer exit code (e.g., Command::SUCCESS, Command::FAILURE).
Instead of:
#[AsCommand(name: 'app:my-command')]
class MyCommand extends Command
{
public function __invoke(): int
{
return null; // or return 'success';
}
}
Use:
#[AsCommand(name: 'app:my-command')]
class MyCommand extends Command
{
public function __invoke(): int
{
return Command::SUCCESS;
// or: Command::FAILURE
// or: Command::INVALID
}
}
2022-03-19
Reports when RequestStack::getCurrentRequest() is called inside a service constructor. The current Request is not available during service construction, resulting in null.
Avoid:
public function __construct(private RequestStack $requestStack)
{
$request = $requestStack->getCurrentRequest(); // Returns null!
}
Instead, inject RequestStack and use it in your methods:
public function someMethod()
{
$request = $this->requestStack->getCurrentRequest();
}
2022-05-31
Reports Console Commands with heavy dependencies in their constructor. Commands with heavy services (like database connections) should be marked as lazy to improve container compilation performance.
See Symfony Documentation for more details.
// Add 'lazy: true' to make the command lazy-loaded:
#[AsCommand(name: 'app:my-command', lazy: true)]
class MyCommand extends Command
{
public function __construct(private HeavyService $service)
{
parent::__construct();
}
}
2022-03-19
Reports when a Session is started or accessed inside a service constructor. The Session may not be available during service construction, similar to the Request.
Avoid:
public function __construct(private SessionInterface $session)
{
$session->set('key', 'value'); // May not work!
}
Use session in your methods instead:
public function someMethod()
{
$this->session->set('key', 'value');
}
2022-03-19
Reports when the security token is fetched via TokenStorageInterface::getToken() inside a constructor. The security context is not yet initialized during service construction.
Avoid:
public function __construct(private TokenStorageInterface $tokenStorage)
{
$token = $tokenStorage->getToken(); // Returns null!
$user = $token->getUser(); // Error!
}
2022-03-19
Reports when the current User is fetched from the TokenStorage in a constructor. The security context (including User) is not available during service construction.
Avoid:
public function __construct(private TokenStorageInterface $tokenStorage)
{
$user = $tokenStorage->getToken()->getUser(); // Error!
}
Use the security helper or fetch user in your methods:
#[Autowire(service: 'security.helper')]
private SecurityHelper $security;
public function someMethod()
{
$user = $this->security->getUser();
}
2022-03-24
Reports Twig extensions with heavy constructor dependencies (like database connections). Twig extensions are instantiated early during container compilation, which can significantly slow down the application if they have complex dependencies.
Consider making your Twig extension lazy-loaded or refactoring to avoid heavy dependencies in the constructor.
See Symfony Documentation for more details.
Avoid:
class MyExtension extends AbstractExtension
{
public function __construct(private ProductRepository $repository) {}
}
Instead, use a runtime loader for lazy loading:
class MyExtension extends AbstractExtension
{
public function getFunctions(): array
{
return [
new TwigFunction('product_count', [ProductRuntime::class, 'getCount']),
];
}
}
class ProductRuntime
{
public function __construct(private ProductRepository $repository) {}
public function getCount(): int
{
return $this->repository->count([]);
}
}
2025-12-01
Reports deprecated usage of arrays as first argument in Symfony Constraint constructors. Symfony deprecated passing constraint options as arrays in favor of named arguments.
Instead of:
new Assert\Choice(['choices' => ['a', 'b']]);
new Assert\NotBlank(['message' => 'This value is required']);
Use:
new Assert\Choice(choices: ['a', 'b']);
new Assert\NotBlank(message: 'This value is required');
2022-03-19
Reports usage of the deprecated kernel.root_dir parameter. Since Symfony 4.2, this parameter is deprecated in favor of kernel.project_dir.
Instead of:
$dir = $this->getParameter('kernel.root_dir');
Use:
$dir = $this->getParameter('kernel.project_dir');
Class does not implement 'Symfony\Component\Form\FormTypeInterface'
FormTypeBuilderInstanceInspection
2022-06-04
FormTypeBuilderInstanceInspection Reports form type classes that do not properly implement Symfony's form type interface. Valid form types must extend AbstractType or implement FormTypeInterface.
// Make sure your form type extends AbstractType:
use Symfony\Component\Form\AbstractType;
class ProductType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('name', TextType::class);
}
}
Previous QueryBuilder method call should be removed, because is overwritten here
DoctrineQueryBuilderAdderInspection
2022-06-01
DoctrineQueryBuilderAdderInspection Reports when Doctrine QueryBuilder method chaining accidentally overwrites previous conditions. Calling where() after andWhere() or orWhere() will reset the WHERE clause.
Incorrect - second where() overwrites andWhere():
$qb->andWhere('x.status = :status')
->where('x.active = true'); // Overwrites previous condition!
Correct - use andWhere/orWhere consistently:
$qb->where('x.active = true')
->andWhere('x.status = :status');
QueryBuilder update()/delete() require alias parameter (Doctrine ORM 3.0)
DoctrineQueryBuilderAliasDeprecationInspection
2025-12-02
DoctrineQueryBuilderAliasDeprecationInspection Reports deprecated usage of Doctrine QueryBuilder update() and delete() methods without providing the alias parameter. In Doctrine ORM 3.0, these methods require the alias parameter to be provided explicitly.
Instead of:
$qb->delete('User u')->where('u.id = :user_id');
$qb->update('User u')->set('u.status', ':status');
Use:
$qb->delete('User', 'u')->where('u.id = :user_id');
$qb->update('User', 'u')->set('u.status', ':status');
QueryBuilder array arguments deprecated (Doctrine DBAL 2.11+)
DoctrineQueryBuilderArrayDeprecationInspection
2025-12-09
DoctrineQueryBuilderArrayDeprecationInspection Reports deprecated array usage in Doctrine DBAL QueryBuilder methods (select(), addSelect(), groupBy(), addGroupBy()). In Doctrine DBAL 2.11+, these methods no longer accept arrays and require individual arguments.
Instead of:
$qb->select(['u.id', 'p.id']);
$qb->addSelect(['u.name', 'p.name']);
$qb->groupBy(['u.category']);
$qb->addGroupBy(['u.status']);
Use:
$qb->select('u.id', 'p.id');
$qb->addSelect('u.name', 'p.name');
$qb->groupBy('u.category');
$qb->addGroupBy('u.status');
2026-01-08
Reports deprecated WITH usage in Doctrine ORM QueryBuilder join methods and DQL for arbitrary joins. Since Doctrine ORM 3.x, WITH should only be used for association joins (defined relations), while ON should be used for arbitrary joins (joins with entity class and join condition). The inspection only triggers when the Doctrine ORM version has this deprecation.
QueryBuilder - Before (Deprecated):
$qb->join(Partner::class, 'p', Expr\Join::WITH, 'p.id = u.myId');
$qb->leftJoin('App\Entity\Geo', 'g', 'WITH', 'g.id = u.geoId');
QueryBuilder - After (Correct):
$qb->join(Partner::class, 'p', Expr\Join::ON, 'p.id = u.myId');
$qb->leftJoin('App\Entity\Geo', 'g', 'ON', 'g.id = u.geoId');
DQL - Before (Deprecated):
$em->createQuery('SELECT u FROM User u JOIN Banlist b WITH u.email = b.email');
$em->createQuery('SELECT u, p FROM User u JOIN ' . CmsPhonenumber::class . ' p WITH u = p.user');
DQL - After (Correct):
$em->createQuery('SELECT u FROM User u JOIN Banlist b ON u.email = b.email');
$em->createQuery('SELECT u, p FROM User u JOIN ' . CmsPhonenumber::class . ' p ON u = p.user');
Association joins (WITH is still valid):
// No warning - this is an association join (u.orders has a defined relation)
$qb->join('u.orders', 'o', 'WITH', 'o.status = :status');
QueryBuilder setParameters() array deprecated (Doctrine ORM 3.0)
DoctrineQueryBuilderSetParametersArrayDeprecationInspection
2025-12-02
DoctrineQueryBuilderSetParametersArrayDeprecationInspection Reports deprecated array usage in Doctrine QueryBuilder setParameters() method. In Doctrine ORM 3.0, setParameters() only accepts ArrayCollection of Parameter objects, not plain arrays.
Instead of:
$qb->setParameters([
'user_id1' => 1,
'user_id2' => 2
]);
Use:
$qb->setParameters(new ArrayCollection([
new Parameter('user_id1', 1),
new Parameter('user_id2', 2)
]));
2026-01-09
Reports empty #[ORM\Table] attributes on Doctrine entities. An empty Table attribute (with no arguments) provides no additional configuration beyond the default table name and can be safely removed. The inspection only reports when an Entity attribute is also present on the class.
Before:
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
#[ORM\Table] class Product
{
// ...
}
After:
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class Product
{
// ...
}
Table attribute is only useful when you need custom configuration:
#[ORM\Entity]
#[ORM\Table(name: 'products', schema: 'app')]
class Product
{
// ...
}
2022-10-20
In controller actions, suggests injecting Request directly instead of RequestStack and then calling getCurrentRequest(). This is cleaner and more straightforward.
Instead of:
public function index(RequestStack $requestStack): Response
{
$request = $requestStack->getCurrentRequest();
$id = $request->query->get('id');
}
Use:
public function index(Request $request): Response
{
$id = $request->query->get('id');
}
Reports deprecated dependency injection patterns in service constructors.
ConstructorDeprecatedInjection
2021-09-29
ConstructorDeprecatedInjection Reports constructor parameters using deprecated classes or interfaces that should no longer be injected directly. Symfony deprecates certain injection patterns in favor of accessing these services through other means for better architecture.
Detected deprecated injections:
SessionInterface- deprecated since Symfony 5.3FlashBagInterface- deprecated since Symfony 5.1
Example 1 - SessionInterface (deprecated since Symfony 5.3):
Instead of:
use Symfony\Component\HttpFoundation\Session\SessionInterface;
class MyService
{
public function __construct(private SessionInterface $session)
{
}
public function doSomething()
{
$this->session->set('key', 'value');
}
}
Use:
use Symfony\Component\HttpFoundation\RequestStack;
class MyService
{
public function __construct(private RequestStack $requestStack)
{
}
public function doSomething()
{
$this->requestStack->getSession()->set('key', 'value');
}
}
Example 2 - FlashBagInterface (deprecated since Symfony 5.1):
Instead of:
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
class MyService
{
public function __construct(private FlashBagInterface $flashBag)
{
}
public function doSomething()
{
$this->flashBag->add('notice', 'Success!');
}
}
Use:
use Symfony\Component\HttpFoundation\RequestStack;
class MyService
{
public function __construct(private RequestStack $requestStack)
{
}
public function doSomething()
{
$this->requestStack->getSession()->getFlashBag()->add('notice', 'Success!');
}
}
2022-11-04
Reports when an exception is instantiated but not thrown. This typically happens when you create an exception object but forget the throw keyword.
Wrong - exception created but not thrown:
new \Exception('Error');
Correct:
throw new \Exception('Error');
2022-11-04
Suggests using built-in AbstractController shortcut methods instead of directly accessing services. Shortcuts like render(), redirect(), json() provide cleaner, more concise code.
Instead of:
return new Response($this->twig->render('template.html.twig'));
Use:
return $this->render('template.html.twig');
'$defaultName' deprecated since Symfony 6.1, use the AsCommand attribute instead
CommandStaticDeprecationInspection
2023-12-17
CommandStaticDeprecationInspection Reports Commands using the deprecated $defaultName and $defaultDescription static properties. Since Symfony 6.1, use the #[AsCommand] attribute instead.
Instead of:
class MyCommand extends Command
{
protected static $defaultName = 'app:my-command';
protected static $defaultDescription = 'My command description';
}
Use:
#[AsCommand(
name: 'app:my-command',
description: 'My command description'
)]
class MyCommand extends Command
{
}
2026-01-06
Reports methods with Doctrine lifecycle callback attributes that are not public. Doctrine lifecycle callback methods (like #[PostLoad], #[PrePersist], etc.) must be public to work correctly.
Instead of:
#[PostLoad]
private function afterLoad(): void
{
// ...
}
Use:
#[PostLoad]
public function afterLoad(): void
{
// ...
}
Entity class must have #[HasLifecycleCallbacks] attribute
DoctrineLifecycleMissingCallbacksAttributeInspection
2026-01-06
DoctrineLifecycleMissingCallbacksAttributeInspection Reports entity classes using Doctrine lifecycle callback attributes (like #[PostLoad], #[PrePersist], etc.) without the #[HasLifecycleCallbacks] attribute. Doctrine requires this attribute on the entity class to enable lifecycle callbacks.
Instead of:
class User
{
#[PostLoad]
public function afterLoad(): void
{
// ...
}
}
Use:
#[HasLifecycleCallbacks]
class User
{
#[PostLoad]
public function afterLoad(): void
{
// ...
}
}
A template that extends another one cannot include content outside Twig blocks
TwigWithExtendsWithRootHtmlInspection
2022-04-17
TwigWithExtendsWithRootHtmlInspection Reports when a template that extends another template has content outside of {% block %} tags. Content outside blocks is ignored and not rendered.
Incorrect - content outside blocks is ignored:
{% extends 'base.html.twig' %}
<div>This content is ignored!</div>
{% block content %}{% endblock %}
Correct - all content inside blocks:
{% extends 'base.html.twig' %}
{% block content %}
<div>This content is rendered.</div>
{% endblock %}
2022-07-11
Reports the deprecated if condition in for loops. Since Twig 2.10, use the filter tag instead.
Deprecated:
{% for item in items if item.active %}
{{ item.name }}
{% endfor %}
Use filter instead:
{% for item in items|filter(item => item.active) %}
{{ item.name }}
{% endfor %}
2020-01-03
Reports deprecated Twig extensions including tags, filters, and functions. The inspection detects usage of deprecated Twig features like {% spaceless %} tag and various deprecated filters/functions.
Deprecated:
{% spaceless %}{{ content }}{% endspaceless %}
{{ content }}
{{ value|deprecated_filter }}
{{ deprecated_function() }}
Use alternative Twig features instead.
2023-07-02
Suggests using path() instead of url() for internal URLs. The path() function generates relative URLs, which is typically what you want for internal links. Use url() only when you need absolute URLs.
For internal links, use path():
<a href="{{ path('product_show', {id: product.id}) }}">View Product</a>
Use url() only when you need absolute URLs (e.g., for emails):
<a href="{{ url('product_show', {id: product.id}) }}">View Product</a>
2016-03-02
Reports deprecated methods and classes used in Twig variables. When accessing properties or calling methods on Twig variables, this inspection detects if the underlying PHP method or class is deprecated.
Example:
{{ user.getDeprecatedMethod() }}
{{ deprecated_service.someMethod() }}
The inspection will warn when calling deprecated methods like:
Method 'User::getDeprecatedMethod' is deprecated
Method 'DeprecatedService::someMethod' is deprecated
2024-03-21
Reports OneToMany relationships without the required mappedBy attribute. In Doctrine, the OneToMany side is always the inverse side and must specify which field on the target entity owns the relationship via ManyToOne.
class Category
{
#[ORM\OneToMany(targetEntity: Product::class, mappedBy: 'category')]
private array $products = [];
}
class Product
{
#[ORM\ManyToOne(targetEntity: Category::class, inversedBy: 'products')]
#[ORM\JoinColumn(name: 'category_id')]
private ?Category $category = null;
}
JoinColumn not allowed on inverse side of one-to-one associations
DoctrineOneToOneOwingSideDeprecationInspection
2023-12-23
DoctrineOneToOneOwingSideDeprecationInspection Reports #[JoinColumn] configuration on the inverse side of one-to-one associations. In Doctrine ORM 3.0+, JoinColumn is only allowed on the owning side of bidirectional one-to-one associations (the side without mappedBy).
Instead of:
#[OneToOne(mappedBy: 'customer')]
#[JoinColumn] // Error: JoinColumn not allowed here
private ?Customer $customer = null;
Use:
#[OneToOne(mappedBy: 'customer')]
private ?Customer $customer = null;
JoinColumn should be on the owning side:
#[OneToOne(inversedBy: 'customer')]
#[JoinColumn]
private ?Address $address = null;
2024-04-04
Suggests using PHP 8.1+ first-class callable syntax instead of callable array notation. First-class callables provide better type safety and are more concise.
Instead of:
array_map([$this, 'processItem'], $items);
Use first-class callable syntax:
array_map($this->processItem(...), $items);
Works with static methods too:
array_map([MyClass::class, 'method'], $items);
// becomes:
array_map(MyClass::method(...), $items);
Full Line Completion: Complete and inject service classes via property
Completion PHP Paid
Annotation namespace will be deprecated in > 6.4/7.0 replace with 'Symfony\Component\Routing\Attribute\Route'
RouteAttributeNamespaceDeprecatedInspection
2023-12-17
RouteAttributeNamespaceDeprecatedInspection Reports usage of the deprecated Symfony\Component\Routing\Annotation\Route namespace. Since Symfony 6.3, Route attributes should use the Attribute namespace instead of Annotation.
Instead of:
use Symfony\Component\Routing\Annotation\Route;
#[Route('/product', name: 'app_product')]
public function index(): Response {}
Use:
use Symfony\Component\Routing\Attribute\Route;
#[Route('/product', name: 'app_product')]
public function index(): Response {}
Full Line Completion: Doctrine QueryBuilder
Completion PHP Paid
Calling clear() with any arguments to clear specific entities is deprecated and will not be supported in Doctrine ORM 3.0.
DoctrineClearParameterDeprecationInspection
2024-04-18
DoctrineClearParameterDeprecationInspection Reports calls to EntityManager::clear() with arguments. Since Doctrine ORM 2.11, calling clear() with entity class names is deprecated and will be removed in Doctrine ORM 3.0.
Instead of:
$entityManager->clear(Foo::class); // Deprecated!
Use:
$entityManager->clear(); // Clears all entities
Or manage entity state manually:
$entityManager->detach($entity);
2017-08-30
Reports when #[Autowire] attributes reference services that don't exist in the container. This helps catch typos or references to services that haven't been registered yet.
#[Autowire(service: 'app.product_repository')] // Service exists
private ProductRepository $productRepository;
#[Autowire(service: 'non_existent_service')] // Error: service not found
private ?SomeService $someService;
2022-06-17
Reports YAML service configurations that reference non-existent container parameters via named arguments (using $parameterName syntax).
# config/services.yaml
parameters:
app.admin_email: 'admin@example.com'
services:
App\Service\NotificationService:
arguments:
$adminEmail: '%app.admin_email%' # Correct
$unknownParam: '%app.unknown%' # Error: parameter doesn't exist
2022-06-16
Reports routes (YAML/XML) that point to controller actions marked with #[Deprecated] attribute. This helps identify outdated routes that should be removed or updated.
The route will be highlighted in your routing configuration with a deprecation warning.
// 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
{
// ...
}
}
Intentions
2025-12-03
Adds a #[Route] attribute to a public method in a Symfony controller class. The route path and name are automatically generated based on the controller and method name.
Before:
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class ProductController extends AbstractController
{
public function index(): Response
{
return $this->render('product/index.html.twig');
}
}
After:
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class ProductController extends AbstractController
{
#[Route('/product', name: 'app_product_index')]
public function index(): Response
{
return $this->render('product/index.html.twig');
}
}
2025-11-29
Converts traditional Symfony Command with execute() method to invokable command style using __invoke() with Argument and Option attributes.
This intention automatically:
- Removes
extends Commandandparent::__construct()calls - Migrates
configure()arguments/options to method parameters with attributes - Replaces
$input->getArgument()and$input->getOption()with direct variable access - Removes redundant type casts and self-assignments
Before:
namespace App\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class CreateUserCommand extends Command
{
public function __construct()
{
parent::__construct();
}
protected function configure(): void
{
$this
->addArgument('username', InputArgument::REQUIRED, 'The username')
->addOption('admin', null, InputOption::VALUE_NONE, 'Make user admin');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$username = $input->getArgument('username');
$isAdmin = $input->getOption('admin');
$output->writeln("Creating user: $username");
if ($isAdmin) {
$output->writeln('User will be admin');
}
return Command::SUCCESS;
}
}
After:
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\Attribute\Argument;
use Symfony\Component\Console\Input\Attribute\Option;
use Symfony\Component\Console\Output\OutputInterface;
class CreateUserCommand
{
public function __construct()
{
}
public function __invoke(
OutputInterface $output,
#[Argument(description: 'The username')]
string $username,
#[Option(description: 'Make user admin')]
bool $admin = false
): int {
$output->writeln("Creating user: $username");
if ($admin) {
$output->writeln('User will be admin');
}
return 0;
}
}
2025-12-03
Adds a supported parameter to invokable Symfony Command __invoke method. The intention is only available when the class does not extend Command and has an __invoke() method.
Before:
<?php
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
#[AsCommand(name: 'app:example')]
class ExampleCommand
{
public function __invoke(): int
{
return 0;
}
}
After:
<?php
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(name: 'app:example')]
class ExampleCommand
{
public function __invoke(SymfonyStyle $io): int
{
return 0;
}
}
2015-02-21
Generates a complete Symfony service definition (YAML or XML) from a PHP class by analyzing the constructor parameters. Opens an interactive dialog that allows customization of service ID and options.
Perfect for quickly creating service definitions for existing PHP classes in Symfony applications.
Before:
# PHP class constructor not in sync with services.yaml
# class OrderProcessor
# {
# public function __construct(
# private LoggerInterface $logger,
# private OrderRepository $orderRepository,
# private EmailService $emailService,
# ) {
# }
# }
services:
App\Service\OrderProcessor:
arguments:
- '@logger'
After:
# Generated service definition (YAML format)
# After using the dialog and clicking "Insert" or "Copy"
services:
App\Service\OrderProcessor:
arguments:
- '@logger'
- '@App\Repository\OrderRepository'
- '@App\Service\EmailService'
2017-10-19
Automatically updates service definition arguments in YAML or XML configuration files to match the constructor parameters of the PHP class. When you modify a service class constructor by adding, removing, or reordering parameters, this intention synchronizes the service definition to match the new constructor signature.
2015-05-01
Creates a new CompilerPass file in the DependencyInjection/Compiler directory and automatically registers it in the bundle's build() method.
Before:
namespace App;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class AppBundle extends Bundle
{
}
After:
namespace App;
use App\DependencyInjection\Compiler\CustomCompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class AppBundle extends Bundle
{
public function build(ContainerBuilder $container): void
{
parent::build($container);
$container->addCompilerPass(new CustomCompilerPass());
}
}
2025-12-04
Adds a parameter (e.g., Request) to a Symfony route action method. Available when the cursor is inside a public method that has a Route attribute or annotation, or inside an __invoke method where the class has a Route attribute or annotation.
Before:
<?php
use Symfony\Component\Routing\Attribute\Route;
class MyController
{
#[Route('/hello')]
public function index(): Response
{
}
}
After:
<?php
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Attribute\Route;
class MyController
{
#[Route('/hello')]
public function index(Request $request): Response
{
}
}
2025-12-10
Migrates Twig Extension from getFilters(), getFunctions(), and getTests() methods to PHP attributes.
Before:
<?php
namespace App\Twig;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Twig\TwigTest;
use Twig\Environment;
class MyExtension extends AbstractExtension
{
public function getFilters()
{
return [
new TwigFilter('filter_name', [$this, 'filterMethod'], ['needs_environment' => true]),
];
}
public function getFunctions()
{
return [
new TwigFunction('function_name', [$this, 'functionMethod'], [
'needs_environment' => true,
'needs_context' => true,
'is_safe' => ['html']
]),
];
}
public function getTests()
{
return [
new TwigTest('test_name', [$this, 'testMethod']),
];
}
public function filterMethod(Environment $env, $value)
{
return $value;
}
public function functionMethod(Environment $env, $context, $value)
{
return $value;
}
public function testMethod($value)
{
return $value;
}
}
After:
<?php
namespace App\Twig;
use Twig\Attribute\AsTwigFilter;
use Twig\Attribute\AsTwigFunction;
use Twig\Attribute\AsTwigTest;
use Twig\Environment;
class MyExtension
{
#[AsTwigFilter('filter_name', needsEnvironment: true)]
public function filterMethod(Environment $env, $value)
{
return $value;
}
#[AsTwigFunction('function_name', needsEnvironment: true, needsContext: true, isSafe: ['html'])]
public function functionMethod(Environment $env, $context, $value)
{
return $value;
}
#[AsTwigTest('test_name')]
public function testMethod($value)
{
return $value;
}
}
2015-04-24
Automatically adds missing service tags to a YAML service definition based on the PHP class's interfaces and attributes. This intention analyzes your PHP class and suggests appropriate tags, opening a popup if multiple tags are detected.
Before:
# config/services.yaml
#
# PHP class implements EventSubscriberInterface:
# class OrderEventSubscriber implements EventSubscriberInterface
# {
# public static function getSubscribedEvents(): array
# {
# return [OrderPlacedEvent::class => 'onOrderPlaced'];
# }
# }
#
# But the service definition is missing the kernel.event_subscriber tag:
services:
App\EventSubscriber\OrderEventSubscriber:
arguments:
- '@logger'
After:
# config/services.yaml
#
# After applying the intention, the kernel.event_subscriber tag is added:
services:
App\EventSubscriber\OrderEventSubscriber:
arguments:
- '@logger'
tags:
- kernel.event_subscriber
2015-04-23
Automatically adds missing <tag> elements to an XML service definition based on the PHP class's interfaces and attributes. This intention analyzes your PHP class and suggests appropriate tags, opening a popup if multiple tags are detected.
Before:
<!-- config/services.xml -->
<!--
PHP class implements EventSubscriberInterface:
class OrderEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [OrderPlacedEvent::class => 'onOrderPlaced'];
}
}
But the service definition is missing the kernel.event_subscriber tag:
-->
<services>
<service id="App\EventSubscriber\OrderEventSubscriber" class="App\EventSubscriber\OrderEventSubscriber">
<argument type="service" id="logger"/>
</service>
</services>
After:
<!-- config/services.xml -->
<!--
After applying the intention, the kernel.event_subscriber tag is added:
-->
<services>
<service id="App\EventSubscriber\OrderEventSubscriber" class="App\EventSubscriber\OrderEventSubscriber">
<argument type="service" id="logger"/>
<tag name="kernel.event_subscriber"/>
</service>
</services>
2015-04-12
Suggests appropriate service IDs for <argument> elements based on the constructor parameter types. Available when your cursor is on an <argument> element.
Before:
<!-- config/services.xml -->
<!--
PHP class constructor:
public function __construct(
private LoggerInterface $logger,
private OrderRepository $orderRepository,
private EmailService $emailService,
) {}
But XML service definition has only one argument:
-->
<services>
<service id="App\Service\OrderProcessor" class="App\Service\OrderProcessor">
<argument type="service" id="logger"/>
</service>
</services>
After:
<!-- config/services.xml -->
<!--
After applying the intention, all constructor arguments are present:
-->
<services>
<service id="App\Service\OrderProcessor" class="App\Service\OrderProcessor">
<argument type="service" id="logger"/>
<argument type="service" id="App\Repository\OrderRepository"/>
<argument type="service" id="App\Service\EmailService"/>
</service>
</services>
2016-03-06
Suggests appropriate service IDs for an <argument> element based on the constructor parameter type. Available when your cursor is on an <argument> element.
Before:
<!-- config/services.xml -->
<services>
<service id="App\Service\OrderProcessor" class="App\Service\OrderProcessor">
<argument type="service" id="logger"/>
<argument/>
<!-- Empty argument - need to fill in service ID -->
</service>
</services>
After:
<!-- config/services.xml -->
<services>
<service id="App\Service\OrderProcessor" class="App\Service\OrderProcessor">
<argument type="service" id="logger"/>
<argument type="service" id="App\Repository\OrderRepository"/>
<!-- Service ID filled in from suggestion popup -->
</service>
</services>
2015-12-13
Converts deprecated shortcut notation like 'AppBundle:Product' or 'App:Product' to Product::class. This modernization provides better refactoring support and is the recommended approach since Doctrine 2.5 and Symfony 4.
Before:
namespace App\Controller;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class ProductController extends AbstractController
{
public function __construct(
private EntityManagerInterface $entityManager
) {
}
public function show(int $id)
{
$repository = $this->entityManager->getRepository('App:Product');
$product = $this->entityManager->find('App:Product', $id);
return $this->render('product/show.html.twig', [
'product' => $product
]);
}
}
After:
namespace App\Controller;
use App\Entity\Product;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class ProductController extends AbstractController
{
public function __construct(
private EntityManagerInterface $entityManager
) {
}
public function show(int $id)
{
$repository = $this->entityManager->getRepository(Product::class);
$product = $this->entityManager->find(Product::class, $id);
return $this->render('product/show.html.twig', [
'product' => $product
]);
}
}
2015-12-12
Converts legacy form type aliases like 'text' to TextType::class.
Before:
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class ProductType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', 'text')
->add('description', 'textarea')
->add('price', 'number')
->add('category', 'entity', [
'class' => 'App\Entity\Category',
])
->add('submit', 'submit');
}
}
After:
namespace App\Form;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
class ProductType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', TextType::class)
->add('description', TextareaType::class)
->add('price', NumberType::class)
->add('category', EntityType::class, [
'class' => 'App\Entity\Category',
])
->add('submit', SubmitType::class);
}
}
2022-04-21
Automatically injects a missing service property through the constructor when you reference $this->serviceProperty that doesn't exist in the class.
Before:
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class ProductController extends AbstractController
{
public function index(): Response
{
$products = $this->productRepository->findAll();
return $this->render('product/index.html.twig', [
'products' => $products
]);
}
}
After:
namespace App\Controller;
use App\Repository\ProductRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class ProductController extends AbstractController
{
public function __construct(
private ProductRepository $productRepository,
) {
}
public function index(): Response
{
$products = $this->productRepository->findAll();
return $this->render('product/index.html.twig', [
'products' => $products
]);
}
}
2017-03-06
Creates a missing translation key in the appropriate translation file when using trans or transchoice filters in Twig templates.
Before:
<h1>product.title</h1>
<p>product.description</p>
<button>product.add_to_cart</button>
After:
# translations/messages.fr.yaml
# After using the intention and entering the French translation:
product:
title: 'Produit'
description: 'Description du produit'
add_to_cart: 'Ajouter au panier'
Completion
Form type class constant completion for builder
Completion PHP
Doctrine entity class constant completion
Completion PHP
Constraint translations message
Completion PHP Navigation
Tag completion inside Attributes
Completion PHP Attribute
Service completion inside Autowire Attribute
Completion PHP Attribute
Parameter completion inside Autowire Attribute
Completion PHP Attribute
Service completion inside Autowire AsDecorator
Completion PHP Attribute
Doctrine QueryBuilder: Field completion
Completion PHP Doctrine
Prioritized extends templates
Completion Twig
Incomplete Yaml named argument
Completion Yaml
!tagged_iterator tag name
Completion Yaml
Prioritized include templates
Completion Twig
Prioritized embed templates
Completion Twig
Incomplete Completion for extends tags
Completion Twig
Incomplete Completion for include tags
Completion Twig
Incomplete Completion for embed tags
Completion Twig
HTML attribute completion with "function print block"
Completion Twig
Navigation
!tagged_iterator tag name
Navigation Yaml
Tag navigation in Attributes
Navigation PHP Attribute
Doctrine QueryBuilder: Field navigation
Navigation PHP Doctrine
Linemarker
Annotation routing loading
Linemarker Yaml XML
Autowired resources classes
Linemarker Yaml XML
Linked class to "data_class" configuration
Linemarker PHP
Generator
Prioritized extends generator
Generator Twig
Block Overwrite
Generator Twig
UX
Component Template Navigation
Linemarker PHP Twig
AsTwigTemplate Template
Completion PHP Twig
Variable Expose
Other Completion Navigation Twig
Component HTML Syntax
Other Navigation Completion Twig
Component Function
Navigation Twig
Incomplete Component Completion
Completion Navigation Twig
2026-01-17
Completion UX Html Twig
Auto-completes Stimulus controller names in HTML data-controller attributes and Twig stimulus_controller() function calls. The completion shows all registered Stimulus controllers from the project, including those from Symfony UX packages.
In HTML, normalized names are provided (e.g., symfony--ux-chartjs--chart). In Twig, both normalized names and original module names (e.g., @symfony/ux-chartjs/chart) are supported. Navigation from controller name to the source JavaScript file is also available.
HTML - data-controller attribute:
<div data-controller="symfony--ux-chartjs--chart">
<canvas data-symfony--ux-chartjs--chart-target="canvas"></canvas>
</div>
Twig - stimulus_controller() function:
{{ stimulus_controller('symfony--ux-chartjs--chart', {
'data': chartData
}) }}
Search Everywhere
Route pattern match search
Other Navigation
MCP Tools
2026-01-11
Lists all Symfony console commands available in the project. This MCP tool provides access to configured console commands with their class names and file paths.
The tool returns CSV format with columns: name, className, filePath.
name,className,filePath
cache:clear,\App\Command\CacheClearCommand,src/Command/CacheClearCommand.php
doctrine:fixtures:load,\Doctrine\Bundle\FixturesBundle\Command\LoadDataFixturesDoctrineCommand,vendor/doctrine/doctrine-fixtures-bundle/Command/LoadDataFixturesDoctrineCommand.php
2026-01-11
Lists all fields of a Doctrine entity as CSV. This MCP tool provides detailed field information for a specific entity class including field names, column names, types, and relations.
The tool returns CSV format with columns: name, column, type, relation, relationType.
name,column,type,relation,relationType
id,id,integer,,
username,username,string,,
email,email,string,,
orders,orders,,App\Entity\Order,OneToMany
2026-01-11
Lists all Doctrine ORM entities in the project as CSV. This MCP tool provides access to all configured Doctrine entities with their class names and file paths.
The tool returns CSV format with columns: className, filePath.
className,filePath
App\Entity\User,src/Entity/User.php
App\Entity\Product,src/Entity/Product.php
App\Entity\Order,src/Entity/Order.php
2026-01-11
Lists all Symfony form types configured in the project. This MCP tool provides access to form type aliases, class names, and their file locations.
The tool returns CSV format with columns: name, className, filePath.
name,className,filePath
user,App\Form\UserType,src/Form/UserType.php
email,Symfony\Component\Form\Extension\Core\Type\EmailType,vendor/symfony/form/Extension/Core/Type/EmailType.php
2026-01-14
Lists all available options for a specific Symfony form type. This MCP tool provides detailed information about option names, their types (DEFAULT, REQUIRED, DEFINED), and the source classes that define them.
The tool accepts a form type name or FQN and returns CSV format with columns: name, type, source.
name,type,source
label,DEFAULT,Symfony\Component\Form\Extension\Core\Type\FormType
required,DEFAULT,Symfony\Component\Form\Extension\Core\Type\FormType
data,DEFAULT,Symfony\Component\Form\Extension\Core\Type\FormType
2026-01-14
Lists the last 10 Symfony profiler requests with detailed information about HTTP requests, controllers, routes, templates, and form types used. This MCP tool provides optional filtering by URL, hash, controller, and route name.
The tool returns CSV format with columns: hash, method, url, statusCode, profilerUrl, controller, route, template, formTypes.
hash,method,url,statusCode,profilerUrl,controller,route,template,formTypes
18e6b8,GET,http://127.0.0.1:8000/user/1,200,_profiler/18e6b8,App\Controller\UserController::show,user_show,user/show.html.twig,
2026-01-11
Lists Symfony routes with their controller mappings and file paths. This MCP tool provides access to routes configured in the Symfony project with optional filtering by route name or controller.
The tool returns CSV format with columns: name, controller, path, filePath.
name,controller,path,filePath
app_home,App\Controller\HomeController::index,/,src/Controller/HomeController.php
api_users_list,App\Controller\UserController::list,/api/users,src/Controller/UserController.php
api_users_show,App\Controller\UserController::show,/api/users/{id},src/Controller/UserController.php
2026-01-11
Matches a plain request URL to Symfony routes using reverse pattern matching. This MCP tool finds routes that could handle a given URL path by matching against route patterns with placeholders.
The tool returns CSV format with columns: name, controller, path, filePath.
name,controller,path,filePath
api_user_show,App\Controller\Api\UserController::show,/api/users/{id},src/Controller/Api/UserController.php
api_user_list,App\Controller\Api\UserController::list,/api/users,src/Controller/Api/UserController.php
2026-01-17
Generates Symfony service definitions in YAML or XML format for a given PHP class. This MCP tool analyzes a class constructor to identify dependencies and creates service arguments for explicit wiring.
The tool supports both YAML (default) and XML output formats, with options to use the class name as service ID or generate a short ID.
YAML example:
App\Service\EmailService:
arguments: ['@mailer', '@logger']
XML example:
<service id="App\Service\EmailService">
<argument type="service" id="mailer"/>
</service>
2026-01-11
Locates where a Symfony service is defined in configuration files by service name or class name. This MCP tool provides access to service definitions with their file paths and line numbers.
The tool returns CSV format with columns: serviceName, className, filePath, lineNumber.
serviceName,className,filePath,lineNumber
app.service.my_service,\App\Service\MyService,config/services.yaml,15
app.my_service_alias,\App\Service\MyService,config/services.yaml,25
2026-01-11
Lists available Twig template extensions for code generation and template assistance. This MCP tool provides unified access to all Twig extensions including filters, functions, tests, and tags.
The tool returns CSV format with columns: extension_type, name, className, methodName, parameters.
extension_type,name,className,methodName,parameters
filter,upper,\Twig\Extension\CoreExtension,upper,"value,encoding"
function,path,\Twig\Extension\AssetExtension,path,"url,name"
filter,date,\Twig\Extension\CoreExtension,date,"date,format"
Other
AssetMapper: importmap function
Completion Navigation Twig
Controller shortcut: renderBlock
Other Completion Navigation PHP
Related template target
Other Twig
Related method targets
Other PHP
2025-12-11
Other Terminal Completion
Provides intelligent code completion for Symfony console commands directly in the integrated terminal. When typing bin/console or console commands, the plugin automatically suggests available commands, and for command options after the command name.
Supports completion for:
- Command names:
bin/console cac<Tab>→ suggestscache:clear,cache:pool:clear, etc. - Command options:
bin/console app:greet Fabien -<Tab>→ suggests available options like--help,--quiet,-v, etc. - Option shortcuts and long forms are both supported
bin/console NAME