根据How to inject a repository into a service in Symfony2? 就像
acme.custom_repository:
class: Doctrine\ORM\EntityRepository
factory: ['@doctrine.orm.entity_manager', getRepository]
arguments:
- 'Acme\FileBundle\Model\File'
但我得到了例外
无效的服务“acme.custom_repository”:class “EntityManager5aa02de170f88_546a8d27f194334ee012bfe64f629947b07e4919__CG __ \原则\ ORM \ EntityManager的” 不存在。
我如何在Symfony 3.4中执行此操作?
EntityClass实际上是一个有效的类FQCN(也可以在phpstorm上使用复制引用),只是重命名它,因为公司名称在其中:)。无论如何更新它。
BlueM的solution效果很好。 如果你没有使用自动装配这里是服务定义:
Acme\AcmeBundle\Respository\MyEntityRepository:
arguments:
- '@Doctrine\Common\Persistence\ManagerRegistry'
- Acme\AcmeBundle\Model\MyEntity # '%my_entity_class_parameter%'
答案 0 :(得分:14)
当您使用Symfony 3.4时,您可以使用更简单的方法,使用ServiceEntityRepository
。只需实现您的存储库,让它extend
类ServiceEntityRepository
,您只需注入它即可。 (至少在使用自动装配时 - 我没有使用经典的DI配置,但会认为它也应该有效。)
换句话说:
namespace App\Repository;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Persistence\ManagerRegistry;
class ExampleRepository extends ServiceEntityRepository
{
/**
* @param ManagerRegistry $managerRegistry
*/
public function __construct(ManagerRegistry $managerRegistry)
{
parent::__construct($managerRegistry, YourEntity::class);
}
}
现在,没有任何DI配置,您可以在任何地方注入存储库,包括控制器方法。
一个警告(同样适用于您尝试注入存储库的方式):如果重置了Doctrine连接,您将引用过时的存储库。但恕我直言,这是我接受的风险,否则我将无法直接注入存储库..
答案 1 :(得分:3)
检查参数是一个有效的类(使用FQCN或简化包),例如:
acme.custom_repository:
class: Doctrine\ORM\EntityRepository
factory:
- '@doctrine.orm.entity_manager'
- getRepository
arguments:
- Acme\MainBundle\Entity\MyEntity
或
acme.custom_repository:
class: Doctrine\ORM\EntityRepository
factory:
- '@doctrine.orm.entity_manager'
- getRepository
arguments:
- AcmeMainBundle:MyEntity
希望这个帮助
答案 2 :(得分:1)
到目前为止,我在这里可以看到的解决方案还不错。我从另一个角度看了看它。因此,我的解决方案可让您保持干净的存储库,sorta强制执行一致的项目结构并保持自动装配!
这就是我在Symfony 5中解决它的方式。
目标
我们想要自动连接存储库,并希望它们保持尽可能干净。我们还希望它们超级易用。
问题
我们需要找出一种方法来告知存储库应使用的实体。
解决方案
该解决方案很简单,包括以下几项内容:
Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository
类。public string $entity
属性。在创建新存储库并扩展自定义存储库类时,我们有两种选择:在新存储库中,我们可以仅指向此类
namespace App\Database\Repository\Post;
use App\Database\Repository\Repository;
use App\Entity\Blog\Post;
/**
* Class PostRepository
* @package App\Database\Repository
*/
class PostRepository extends Repository
{
public string $entity = Post::class;
public function test()
{
dd(99999, $this->getEntityName());
}
}
或者我们可以省略该属性,并让我们的新基础Repository类自动找到它! (稍后会详细介绍。)
代码
所以让我们从代码开始,然后我将对其进行解释:
<?php
namespace App\Database\Repository;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Laminas\Code\Reflection\ClassReflection;
use Symfony\Component\Finder\Finder;
/**
* Class Repository
* @package App\Database\Repository
*/
abstract class Repository extends ServiceEntityRepository
{
/** @var string */
private const REPOSITORY_FILE = 'repository';
/** @var string */
public string $entity = '';
/** @var string */
public string $defaultEntitiesLocation;
/** @var string */
public string $defaultEntitiesNamespace;
/**
* Repository constructor.
*
* @param ManagerRegistry $registry
* @param $defaultEntitiesLocation
* @param $defaultEntitiesNamespace
* @throws \Exception
*/
public function __construct(
ManagerRegistry $registry,
$defaultEntitiesLocation,
$defaultEntitiesNamespace
) {
$this->defaultEntitiesLocation = $defaultEntitiesLocation;
$this->defaultEntitiesNamespace = $defaultEntitiesNamespace;
$this->findEntities();
parent::__construct($registry, $this->entity);
}
/**
* Find entities.
*
* @return bool
* @throws \ReflectionException
*/
public function findEntities()
{
if (class_exists($this->entity)) {
return true;
}
$repositoryReflection = (new ClassReflection($this));
$repositoryName = strtolower(preg_replace('/Repository/', '', $repositoryReflection->getShortName()));
$finder = new Finder();
if ($finder->files()->in($this->defaultEntitiesLocation)->hasResults()) {
foreach ($finder as $file) {
if (strtolower($file->getFilenameWithoutExtension()) === $repositoryName) {
if (!empty($this->entity)) {
throw new \Exception('Entity can\'t be matched automatically. It looks like there is' .
' more than one ' . $file->getFilenameWithoutExtension() . ' entity. Please use $entity
property on your repository to provide entity you want to use.');
}
$namespacePart = preg_replace(
'#' . $this->defaultEntitiesLocation . '#',
'',
$file->getPath() . '/' . $file->getFilenameWithoutExtension()
);
$this->entity = $this->defaultEntitiesNamespace . preg_replace('#/#', '\\', $namespacePart);
}
}
}
}
}
好,那么这里发生了什么?我已经将一些值绑定到services.yml
中的容器:
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
bind:
$defaultEntitiesLocation: '%kernel.project_dir%/src/Entity'
$defaultEntitiesNamespace: 'App\Entity'
然后在我们的新扩展类中,我知道默认情况下在哪里查找我的实体(这会保持一定的一致性)。
非常重要的位-我假设我们将使用完全相同的名称来命名存储库和实体,例如:Post
将是我们的实体,PostRepository
是我们的存储库。请注意,Repository
一词不是必须的。如果有,它将被删除。
一些聪明的逻辑会为您创建名称空间-我假设您将遵循一些良好做法,并且它们将保持一致。
完成了!要使存储库自动连线,您需要做的就是扩展新的基本存储库类,并将Entity命名为与存储库相同的名称。所以最终结果如下:
<?php
namespace App\Database\Repository\Post;
use App\Database\Repository\Repository;
use App\Entity\Blog\Post;
/**
* Class PostRepository
* @package App\Database\Repository
*/
class PostRepository extends Repository
{
public function test()
{
dd(99999, $this->getEntityName());
}
}
这是清洁,自动装配,超级容易且快速创建的!
答案 3 :(得分:0)
首先,您需要创建从doctrine扩展默认存储库的存储库自定义类:
use Doctrine\ORM\EntityRepository;
class UserRepository extends EntityRepository
{
// your own methods
}
然后你需要在实体类中使用这个注释:
/**
* @ORM\Entity(repositoryClass="MyDomain\Model\UserRepository")
*/
然后在.yml文件中定义存储库:
custom_repository:
class: MyDomain\Model\UserRepository
factory: ["@doctrine", getRepository]
arguments:
- Acme\FileBundle\Model\File
确保您的存储库class
的定义指向您的自定义存储库类,而不是Doctrine\ORM\EntityRepository
。
在自定义存储库中为您的服务创建自定义设置器
使用Doctrine \ ORM \ EntityRepository;
class UserRepository extends EntityRepository
{
protected $paginator;
public function setPaginator(PaginatorInterface $paginator)
{
$this->paginator = $paginator;
}
}
然后像这样注射它们:
custom_repository:
class: MyDomain\Model\UserRepository
factory: ["@doctrine", getRepository]
arguments:
- Acme\FileBundle\Model\File
calls:
- [setPaginator, ['@knp_paginator']]
my_custom_service:
class: Acme\FileBundle\Services\CustomService
arguments:
- "@custom_repository"