Новая альтернатива для getDoctrine() в Symfony 5.4 и выше

#symfony #doctrine

#php #symfony #доктрина #symfony5

Вопрос:

Как указывает моя среда разработки, этот AbstractController::getDoctrine() метод теперь устарел.

Я не нашел никаких ссылок на это устаревание ни в официальной документации, ни в списке изменений Github.

Какова новая альтернатива или обходной путь для этого ярлыка?

Ответ №1:

Как упоминалось здесь:

Вместо того, чтобы использовать эти ярлыки, внедрите соответствующие службы в методы конструктора или контроллера.

Вам нужно использовать внедрение зависимостей.

Для данного контроллера просто введите ManagerRegistry конструктор контроллера.

 
use DoctrinePersistenceManagerRegistry;

class SomeController {

    public function __construct(private ManagerRegistry $doctrine) {}

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

Комментарии:

1. Могу ли я спросить, в чем разница между EntityManagerInterface и ManagerRegistry и почему последний вариант лучше?

2. Я не знаю, «лучше» ли это. Это просто эквивалентно старому поведению getDoctrine() . Также можно внедрить EntityManagerInterface . Посмотрите, что работает лучше для вас, в зависимости от ваших потребностей. Проверьте, что предоставляет каждый сервис.

3. ManagerRegistry позволяет извлекать EntityManagerInterface менеджеры, отличные от стандартных, если вы их используете. Если у вас только один менеджер, внедрение EntityManagerInterface подойдет. Проверьте исходный код для обоих интерфейсов, чтобы увидеть, в чем разница. Например, вы не можете сохранять или удалять напрямую, используя ManagerRegistry объект. Вы должны сделать это через объект, созданный ManagerRegistry::getManager() . В конце концов, не имеет большого значения, какой из них вы выберете. Выберите менее подробный или лучше подходящий для вашего варианта использования.

Ответ №2:

Вы можете использовать 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);
}
 

Ответ №3:

Согласно ответу @yivi и, как указано в документации, вы также можете следовать приведенному ниже примеру, вводя DoctrinePersistenceManagerRegistry непосредственно в нужный вам метод:

 // src/Controller/ProductController.php
namespace AppController;

// ...
use AppEntityProduct;
use DoctrinePersistenceManagerRegistry;
use SymfonyComponentHttpFoundationResponse;

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

Ответ №4:

В моем случае полагаться на автоматическую проводку на основе конструктора или метода недостаточно гибко.

У меня есть черта, используемая рядом контроллеров, которые определяют свою собственную автоматическую проводку. Функция предоставляет метод, который извлекает некоторые числа из базы данных. Я не хотел жестко связывать функциональность функции с настройкой автоматического подключения контроллера.

Я создал еще одну черту, которую я могу включить в любое место, где мне нужно получить доступ к Doctrine. Бонусная часть? Это все еще законный подход к автоматической проводке:

 <?php

namespace AppController;

use DoctrinePersistenceManagerRegistry;
use DoctrinePersistenceObjectManager;
use SymfonyContractsServiceAttributeRequired;

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);
    }
}
 

и затем

 
<?php

namespace AppController;

use SymfonyBundleFrameworkBundleControllerAbstractController;
use AppEntityFoobar;

class SomeController extends AbstractController
{
    use EntityManagerTrait

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

Если у вас есть несколько менеджеров, как у меня, вы также можете использовать getDoctrine() аргументы для выбора нужного.