Hub*_*ron 26 symfony doctrine-orm
是否有一种简单的方法将依赖注入到Doctrine2中的每个存储库实例中?
我已经尝试过监听loadClassMetadata
事件并在存储库上使用setter注入,但这自然导致无限循环,因为getRepository
事件中的调用触发了同一事件.
在看了一下这个Doctrine\ORM\EntityManager::getRepository
方法之后,看起来存储库根本就没有使用依赖注入,而是在函数级别实例化它们:
public function getRepository($entityName)
{
$entityName = ltrim($entityName, '\\');
if (isset($this->repositories[$entityName])) {
return $this->repositories[$entityName];
}
$metadata = $this->getClassMetadata($entityName);
$customRepositoryClassName = $metadata->customRepositoryClassName;
if ($customRepositoryClassName !== null) {
$repository = new $customRepositoryClassName($this, $metadata);
} else {
$repository = new EntityRepository($this, $metadata);
}
$this->repositories[$entityName] = $repository;
return $repository;
}
Run Code Online (Sandbox Code Playgroud)
有任何想法吗 ?
Ald*_*nio 35
问题是存储库类不是Symfony2代码库的一部分,因为它们是Doctrine2的一部分,因此它们不利用DIC; 这就是为什么你不能在一个地方为所有存储库注射的原因.
我建议你使用不同的方法.例如,您可以在存储库之上创建服务层,并实际通过该层中的工厂注入所需的类.
否则,您也可以通过这种方式将存储库定义为服务:
<service id="your_namespace.repository.repos_name"
class="%your_namespace.repository.repos_name%"
factory-service="doctrine" factory-method="getRepository">
<argument>entity_name</argument>
<argument>entity_manager_name</argument>
<call method="yourSetter">
<argument>your_argument</argument>
</call>
</service>
Run Code Online (Sandbox Code Playgroud)
可以集中设置方法调用的解决方案是编写DIC标记和编译器传递来处理它并标记所有存储库服务.
sam*_*ime 16
这是Aldo答案的YAML版本,以防您使用YAML配置而不是XML
your_namespace.repository.repos_name:
class: %your_namespace.repository.repos_name%
factory: ["@doctrine", getRepository]
arguments:
- entity_name
- entity_manager_name
calls:
- [setContainer, ["@service_container"]]
Run Code Online (Sandbox Code Playgroud)
在版本2.8之前:
your_namespace.repository.repos_name:
class: %your_namespace.repository.repos_name%
factory_service: doctrine
factory_method: getRepository
arguments:
- entity_name
- entity_manager_name
calls:
- [setContainer, [@service_container]]
Run Code Online (Sandbox Code Playgroud)
另外,作为注释,entity_manager_name是可选参数.我想要我的特定用途的默认值,所以我把它留空(以防我重命名默认管理器).
Ste*_*nte 10
如果使用自定义EntityManager,则可以覆盖该getRepository
方法.由于这不涉及loadClassMetadata
事件,因此您不会遇到无限循环.
首先必须将依赖项传递给自定义EntityManager,然后使用setter注入将其传递给存储库对象.
我在这里回答了如何使用自定义EntityManager ,但我将复制以下答案:
1 - 覆盖doctrine.orm.entity_manager.class
参数以指向您的自定义实体管理器(应该扩展)Doctrine\ORM\EntityManager
.
2 - 您的自定义实体管理器必须覆盖该create
方法,以便它返回您的类的实例.请参阅下面的示例,并注意最后一行MyEntityManager
:
public static function create($conn, Configuration $config, EventManager $eventManager = null) {
if (!$config->getMetadataDriverImpl()) {
throw ORMException::missingMappingDriverImpl();
}
if (is_array($conn)) {
$conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, ($eventManager ? : new EventManager()));
} else if ($conn instanceof Connection) {
if ($eventManager !== null && $conn->getEventManager() !== $eventManager) {
throw ORMException::mismatchedEventManager();
}
} else {
throw new \InvalidArgumentException("Invalid argument: " . $conn);
}
// This is where you return an instance of your custom class!
return new MyEntityManager($conn, $config, $conn->getEventManager());
}
Run Code Online (Sandbox Code Playgroud)
您还需要use
在课堂上进行以下操作:
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\ORMException;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Connection;
Run Code Online (Sandbox Code Playgroud)
编辑
由于默认实体管理器是从该create
方法创建的,因此您不能简单地将服务注入其中.但是,由于您正在创建自定义实体管理器,因此可以将其连接到服务容器并注入所需的任何依赖项.
然后从被覆盖的getRepository
方法中你可以做类似的事情
$repository->setFoo($this->foo)
.这是一个非常简单的例子 - 您可能希望在调用之前首先检查是否$repository
有setFoo
方法.实现取决于您,但这显示了如何对存储库使用setter注入.
归档时间: |
|
查看次数: |
20252 次 |
最近记录: |