3slab / vdm-library-doctrine-transport-bundle

Vdm Doctrine Transport

3.0.0 2021-06-08 07:21 UTC

This package is auto-updated.

Last update: 2024-09-15 22:37:18 UTC


README

Build Status

安装

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 方法。

多字段与自然获取器

如果没有单列主键(例如:没有键或复合键),则可以采取另一种方法,并告诉执行者哪些字段应用于检索现有实体。例如,如果您的实体有两个代表其身份的字段(让我们说 codehash),并且它们都具有自然获取器(即 getCodegetHash),则您需要按如下方式配置选项

framework:
    messenger:
        transports:
            producer:
                dsn: vdm+doctrine://
                options:
                    entities:
                        App\Entity\Demande:
                            selector:
                                - code
                                - hash

底层,存储库将像这样调用

$repo->findOneBy([ 'code' => $yourEntity->getCode(), 'hash' => $yourEntity->getHash() ])

注意:注意 findOneBy。发送者将使用第一个匹配的实体。您负责提供一组唯一的过滤器。

多字段与非常规获取器

如果与身份相关的字段具有非常规获取器(例如:旧代码、多语言代码),则可以定义用于检索适当属性的获取器。假设身份由两个字段组成:labelhash,它们各自的获取器是 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(每个生产者一个),并将正确的消息路由到正确的产品。