3slab / vdm-library-doctrine-transport-bundle
Vdm Doctrine Transport
Requires
- ext-json: *
- 3slab/vdm-library-bundle: ^3.0
Requires (Dev)
- ext-curl: *
- ext-mbstring: *
- ext-xml: *
- phpunit/phpunit: ^9
- squizlabs/php_codesniffer: ^3.6
Suggests
- doctrine/mongodb-odm-bundle: if you wen to persist your entities using ODM document manager
- symfony/orm-pack: if you wen to persist your entities using ORM entity manager
This package is auto-updated.
Last update: 2024-09-15 22:37:18 UTC
README
安装
composer require 3slab/vdm-library-doctrine-transport-bundle
您需要安装 doctrine ORM 或 ODM 之一(或两者都安装)
composer require symfony/orm-pack
或者
composer require doctrine/mongodb-odm-bundle
配置参考
配置分为两部分:传输和 Doctrine 的行为。
传输
在 messenger.yaml
中
framework: messenger: transports: producer: dsn: vdm+doctrine_orm://mycustomconnection options: doctrine_executor: ~ default_entity: ~ entities: App\Entity\Demande: selector: RefDemande
检索现有实体
在持久化任何内容之前,此传输将始终尝试查找现有实体。您需要告诉它如何进行操作。您有几种方法可以做到这一点。
自然方式
这意味着您的实体包含一个唯一标识符值,例如
/** * @ORM\Id() */ private $id;
如果此值由传入的消息携带,则无需进行配置。您的唯一责任是确保该属性有公共获取器(如果没有,您将收到明确的错误消息)。
注意:在这种情况下,发送者将使用存储库上的 find
方法。
多字段与自然获取器
如果没有单列主键(例如:没有键或复合键),则可以采取另一种方法,并告诉执行者哪些字段应用于检索现有实体。例如,如果您的实体有两个代表其身份的字段(让我们说 code
和 hash
),并且它们都具有自然获取器(即 getCode
和 getHash
),则您需要按如下方式配置选项
framework: messenger: transports: producer: dsn: vdm+doctrine:// options: entities: App\Entity\Demande: selector: - code - hash
底层,存储库将像这样调用
$repo->findOneBy([ 'code' => $yourEntity->getCode(), 'hash' => $yourEntity->getHash() ])
注意:注意 findOneBy
。发送者将使用第一个匹配的实体。您负责提供一组唯一的过滤器。
多字段与非常规获取器
如果与身份相关的字段具有非常规获取器(例如:旧代码、多语言代码),则可以定义用于检索适当属性的获取器。假设身份由两个字段组成:label
和 hash
,它们各自的获取器是 getLibelle()
和 hash()
。您将需要按照如下方式配置发送者
framework: messenger: transports: producer: dsn: vdm+doctrine:// options: entities: App\Entity\Demande: selector: label: getLibelle hash: hash
底层,存储库将像这样调用
$repo->findOneBy([ 'label' => $yourEntity->getLibelle(), 'hash' => $yourEntity->hash() ])
相同的策略适用于自然获取器:您必须确保它返回尽可能唯一的东西。
您可以同时定义多个实体,并且可以混合自然和非自然获取器。但是,您必须使用整数键来前缀您的自然获取器。键本身并不重要(只要您不创建重复项),它只需要是一个整数。如果键是整数,则将猜测获取器。否则,获取器将是您提供的
framework: messenger: transports: producer: dsn: vdm+doctrine:// options: entities: App\Entity\Foo: selector: 0: code # hack to mix natural and non-natural getters label: getLibelle #non natural getter hash: hash #non natural getter App\Entity\Bar: ~ # Bar has a single-field identity (id) with natural getter, no configuration needed App\Entity\Baz: selector: - reference # Baz uses a filter based on its reference with natural getter (getReference)
底层,存储库将像这样检索实体
// Foo $repo->findOneBy([ 'code' => $foo->getCode(), 'label' => $foo->getLibelle(), 'hash' => $foo->hash() ]); // Bar $repo->find($bar->getId()); // Baz $repo->findOneBy([ 'reference' => $baz->getReference() ]);
Doctrine 执行器
Doctrine 执行器允许您通过 messenger.yaml
文件中的传输定义自定义 doctrine ORM 传输的行为。
如果您在声明传输时未设置自定义 doctrine_executor
选项,则使用默认的 DefaultDoctrineExecutor。
您可以通过提供一个扩展 Vdm\Bundle\LibraryDoctrineTransportBundle\Executor\AbstractDoctrineExecutor
的类的类来覆盖此行为。
namespace App\Executor\Doctrine; use Vdm\Bundle\LibraryDoctrineTransportBundle\Executor\AbstractDoctrineExecutor; use Vdm\Bundle\LibraryBundle\Model\Message; class CustomDoctrineExecutor extends AbstractDoctrineExecutor { public function execute(Message $message): void { if (!$this->manager) { throw new NoConnectionException('No connection was defined.'); } $entityMetadatas = $message->getMetadatasByKey('entity'); $entityMetadata = array_shift($entityMetadatas); $entityClass = $entityMetadata->getValue(); $entity = $this->serializer->denormalize($message->getPayload(), $entityClass); $entity = $this->matchEntity($entity); $this->manager->persist($entity); $this->manager->flush(); } }
然后在项目中的传输定义中引用此自定义执行器
framework: messenger: transports: store-entity: options: doctrine_executor: App\Executor\Doctrine\CustomDoctrineExecutor
实体/文档匹配
为了让传输知道应将有效载荷持久化到哪些实体或文档,您可以选择
- 在消息的元数据中提供实体的完全限定类名,使用键
entity
。例如new Metadata('entity', 'App\Entity\Foo')
。 - 在传输级别配置默认实体
framework: messenger: transports: store-entity: options: default_entity: App\Entity\Foo
限制
您不能在单个传输中使用不同的连接来连接不同的实体。如果您有这样的需求,您应该为每个连接定义一个传输,扩展库的 Message(每个生产者一个),并将正确的消息路由到正确的产品。