'New alternative for getDoctrine() in Symfony 5.4 and up

As my IDE points out, the AbstractController::getDoctrine() method is now deprecated.

I haven't found any reference for this deprecation neither in the official documentation nor in the Github changelog.

What is the new alternative or workaround for this shortcut?



Solution 1:[1]

As mentioned here:

Instead of using those shortcuts, inject the related services in the constructor or the controller methods.

You need to use dependency injection.

For a given controller, simply inject ManagerRegistry on the controller's constructor.


use Doctrine\Persistence\ManagerRegistry;

class SomeController {

    public function __construct(private ManagerRegistry $doctrine) {}

    public function someAction(Request $request) {
        // access Doctrine
        $this->doctrine;
    }
} 

Solution 2:[2]

You can use EntityManagerInterface $entityManager:

public function delete(Request $request, Test $test, EntityManagerInterface $entityManager): Response
{
    if ($this->isCsrfTokenValid('delete'.$test->getId(), $request->request->get('_token'))) {
        $entityManager->remove($test);
        $entityManager->flush();
    }

    return $this->redirectToRoute('test_index', [], Response::HTTP_SEE_OTHER);
}

Solution 3:[3]

As per the answer of @yivi and as mentionned in the documentation, you can also follow the example below by injecting Doctrine\Persistence\ManagerRegistry directly in the method you want:

// src/Controller/ProductController.php
namespace App\Controller;

// ...
use App\Entity\Product;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\HttpFoundation\Response;

class ProductController extends AbstractController
{
    /**
     * @Route("/product", name="create_product")
     */
    public function createProduct(ManagerRegistry $doctrine): Response
    {
        $entityManager = $doctrine->getManager();

        $product = new Product();
        $product->setName('Keyboard');
        $product->setPrice(1999);
        $product->setDescription('Ergonomic and stylish!');

        // tell Doctrine you want to (eventually) save the Product (no queries yet)
        $entityManager->persist($product);

        // actually executes the queries (i.e. the INSERT query)
        $entityManager->flush();

        return new Response('Saved new product with id '.$product->getId());
    }
}

Solution 4:[4]

In my case, relying on constructor- or method-based autowiring is not flexible enough.

I have a trait used by a number of Controllers that define their own autowiring. The trait provides a method that fetches some numbers from the database. I didn't want to tightly couple the trait's functionality with the controller's autowiring setup.

I created yet another trait that I can include anywhere I need to get access to Doctrine. The bonus part? It's still a legit autowiring approach:

<?php

namespace App\Controller;

use Doctrine\Persistence\ManagerRegistry;
use Doctrine\Persistence\ObjectManager;
use Symfony\Contracts\Service\Attribute\Required;

trait EntityManagerTrait
{
    protected readonly ManagerRegistry $managerRegistry;

    #[Required]
    public function setManagerRegistry(ManagerRegistry $managerRegistry): void
    {
        // @phpstan-ignore-next-line PHPStan complains that the readonly property is assigned outside of the constructor.
        $this->managerRegistry = $managerRegistry;
    }

    protected function getDoctrine(?string $name = null, ?string $forClass = null): ObjectManager
    {
        if ($forClass) {
            return $this->managerRegistry->getManagerForClass($forClass);
        }

        return $this->managerRegistry->getManager($name);
    }
}

and then


<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use App\Entity\Foobar;

class SomeController extends AbstractController
{
    use EntityManagerTrait

    public function someAction()
    {
        $result = $this->getDoctrine()->getRepository(Foobar::class)->doSomething();
        // ...
    }
}

If you have multiple managers like I do, you can use the getDoctrine() arguments to fetch the right one too.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 commonpike
Solution 2 Cadot.eu
Solution 3 fallais
Solution 4 Jan Klan