Symfony 5.4 及更高版本中 getDoctrine() 的新替代方案
New alternative for getDoctrine() in Symfony 5.4 and up
正如我的 IDE 指出的那样,AbstractController::getDoctrine()
方法现已弃用。
我在官方文档和 Github 变更日志中都没有找到任何关于此弃用的参考。
此快捷方式的新替代方案或解决方法是什么?
如前所述here:
Instead of using those shortcuts, inject the related services in the constructor or the controller methods.
您需要使用依赖注入。
对于给定的控制器,只需在控制器的构造函数中注入 ManagerRegistry
。
use Doctrine\Persistence\ManagerRegistry;
class SomeController {
public function __construct(private ManagerRegistry $doctrine) {}
public function someAction(Request $request) {
// access Doctrine
$this->doctrine;
}
}
您可以使用 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);
}
根据@yivi 的回答和documentation中提到的,你也可以按照下面的例子直接在你想要的方法中注入Doctrine\Persistence\ManagerRegistry
:
// 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());
}
}
在我的例子中,依靠构造函数或 method-based 自动装配不够灵活。
我有一个特性被许多控制器使用,它们定义了自己的自动装配。该特征提供了一种从数据库中获取一些数字的方法。我不想将特征的功能与控制器的自动装配设置紧密结合。
我创建了另一个特征,我可以将其包含在任何我需要访问 Doctrine 的地方。奖金部分?它仍然是一种合法的自动装配方法:
<?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);
}
}
然后
<?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();
// ...
}
}
如果您像我一样有多名经理,您也可以使用 getDoctrine()
参数来获取正确的经理。
正如我的 IDE 指出的那样,AbstractController::getDoctrine()
方法现已弃用。
我在官方文档和 Github 变更日志中都没有找到任何关于此弃用的参考。
此快捷方式的新替代方案或解决方法是什么?
如前所述here:
Instead of using those shortcuts, inject the related services in the constructor or the controller methods.
您需要使用依赖注入。
对于给定的控制器,只需在控制器的构造函数中注入 ManagerRegistry
。
use Doctrine\Persistence\ManagerRegistry;
class SomeController {
public function __construct(private ManagerRegistry $doctrine) {}
public function someAction(Request $request) {
// access Doctrine
$this->doctrine;
}
}
您可以使用 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);
}
根据@yivi 的回答和documentation中提到的,你也可以按照下面的例子直接在你想要的方法中注入Doctrine\Persistence\ManagerRegistry
:
// 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());
}
}
在我的例子中,依靠构造函数或 method-based 自动装配不够灵活。
我有一个特性被许多控制器使用,它们定义了自己的自动装配。该特征提供了一种从数据库中获取一些数字的方法。我不想将特征的功能与控制器的自动装配设置紧密结合。
我创建了另一个特征,我可以将其包含在任何我需要访问 Doctrine 的地方。奖金部分?它仍然是一种合法的自动装配方法:
<?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);
}
}
然后
<?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();
// ...
}
}
如果您像我一样有多名经理,您也可以使用 getDoctrine()
参数来获取正确的经理。