electricmaxxx/doctrine-orm-odm-adapter

在ORM上使用ODM的映射

dev-master / 1.0.x-dev 2016-05-10 18:48 UTC

This package is auto-updated.

Last update: 2024-09-12 03:28:28 UTC


README

Build Status

我在一个客户项目中意识到,有一些用例需要在实体(即ORM)上引用文档(即从phpcr-odm)。引用是通过文档的uuid完成的。因此,我首先实现了一个监听器,该监听器根据持久化的uuid处理实体的文档的加载、持久化和删除。

由于这种处理可能会越来越复杂,我看到了创建映射的需求。因此,这个库就诞生了。目前,我正在尝试映射以下字段/属性

  • uuid - 实体上uuid的字段
  • document - 实体上文档的字段
  • common-field - 应在文档和实体上同步的字段,例如标题,以便在仅显示时不加载整个文档

当前状态

用法

配置

要创建一个ObjectAdapterManager的新实例,您需要设置一些简单的配置。该类可以不设置这些配置而工作,但您将没有任何管理器来持久化您引用的对象

     use Doctrine\Common\Annotations\AnnotationReader;
     use Doctrine\Common\Cache\ArrayCache;
     use Doctrine\Common\EventManager;
     use Doctrine\ODM\PHPCR\DocumentManager;
     use Doctrine\ORM\EntityManager;
     use Doctrine\ORM\ODMAdapter\Mapping\Driver\AnnotationDriver;
     use Doctrine\ORM\ODMAdapter\ObjectAdapterManager;
     use Doctrine\Common\EventManager;

     // caching and annotation read
     $cache = new ArrayCache();
     $reader = new AnnotationReader($cache);

     // AnnotationDriver as example, Yaml and Xml available too
     $annotationDriver = new AnnotationDriver($reader);
     $annotationDriver->addPaths(array(__DIR__ . "/Models"));

     // configuration for the manager
     $configuration = new Configuration();
     $configuration->setManagers(
        array(
            'reference-phpcr' => array(
                'default'  => $documentManager,
            ),
            'reference-dbal-orm' => array(
                'defaulKt'  => $entityManager,
            ),
        )
     );
     $configuration->setClassMetadataFactoryName('Doctrine\ORM\ODMAdapter\Mapping\ClassMetadataFactory');
     $configuration->setMetadataDriverImpl($annotationDriver);

     // create the ObjectAdapterManager with the configuration and optional event manager
     $objectAdapterManager = ObjectAdapterManager::create($configuration, new EventManager());

     // makes it possible to use the library's own event subscribers for the managers lifecycle events
     $objectAdapterManager->addListenersToEventManagers();

该配置看起来非常类似于常见的doctrine配置,这也是目的所在。还有两个额外的映射驱动程序可用。一个是Yaml,另一个是Xml。有一个区别:您必须设置您想要使用的管理器,用于对象的引用以及引用对象。管理器按映射类型(reference-phpcr和reference-dbal-orm)和名称排序。

此库的主要目的是,以下示例可以在不针对引用对象进行任何操作的情况下工作

     $entity = new ReferencingEntity();

     $document = new ReferencedDocument();
     $document->name = 'document-name';
     $document->parentDocument =  // create some parent document
     $entity->document = $this->referencedObject;

     $entityManager->persist($entity);
     $entityManager->flush();
     $entityManager->clear();

     $document = $documentManager->find(null, '/some-path/document-name');

     // or even better
     $entity = $entityManager->find('Entity', $entity->id);
     $document = $entity->document;

一般来说,本文档讨论的对象引用了引用对象,但示例试图用引用文档的实体(或相反)来解释这一点。但这个示例应该如何工作?我们可以为每个用例进行一些自定义事件挂钩,或者只是手动持久化引用对象。

映射

但此库的映射应该有助于这种情况。您可以用Xml进行


    <?xml version="1.0" encoding="UTF-8"?>
    <doctrine-mapping
            xmlns="http://doctrine-project.org/schemas/orm-odm-adapter/adapter-mapping"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://doctrine-project.org/schemas/orm-odm-adapter/adapter-mapping
            https://github.com/ElectricMaxxx/DoctrineOrmOdmAdapter/blob/master/doctrine-orm-odm-adapter-mapping.xsd ">
        <object-adapter name="Entity">
            <reference-phpcr
                    target-object="Document"
                    referenced-by="uuid"
                    inversed-by="uuid"
                    name="document"
                    manager="default">
            </reference-phpcr>
        </object-adapter>
    </doctrine-mapping>

Yaml


    Doctrine\Tests\ORM\ODMAdapter\Mapping\Driver\Model\ReferenceMappingObject:
      referencedField:
          type: reference-phpcr
          referenced-by: uuid
          inversed-by: uuid
          target-object: Document

或注解

    use Doctrine\ORM\ODMAdapter\Mapping\Annotations as ODMAdapter;

     /**
      * @ODMAdapter\ObjectAdapter
      */
     class Entity
     {
         public $uuid;

         /**
          * @ODMAdapter\ReferencePhpcr(
          *  referencedBy="uuid",
          *  inversedBy="uuid",
          *  targetObject="Document",
          *  manager="default"
          * )
          */
         public $document;
     }

引用映射由一个项(xml节点、注解等)包装,该项描述了引用的类型,即引用对象所在的doctrine。目前有两种不同的类型可用

  • reference-phpcr -> 创建一个使用phpcr-odm持久化的文档的引用
  • reference-dbal-orm -> 创建一个使用doctrines orm持久化的实体的引用

这些类型的主体具有相同的属性

  • referenced-by -> 引用对象的标识符($manager->find(null, $id))应该工作)
  • inversed-by -> 存储引用对象(referenced-by)的字段值的字段
  • target-object -> 引用对象的FQCN
  • name -> 查找引用对象的字段
  • 通用字段 -> 在两个对象之间保持同步的字段(请参阅自身描述)

如果您为配置设置的经理提供了自己的事件经理,那么这已经足够了。该库能够将自定的EventSubscriber挂钩到持有引用的对象的UnitOfWork触发的事件周期中。否则,您需要构建自己的事件系统,并在ObjectAdapterManager上调用相应的方法。只需以库自带的为例

     <?php

     namespace Doctrine\ORM\ODMAdapter\Event;

     use Doctrine\Common\Persistence\Event\ManagerEventArgs;
     use Doctrine\ORM\Event\PreFlushEventArgs;
     use Doctrine\ORM\Event\LifecycleEventArgs;
     use Doctrine\ORM\Event\OnClearEventArgs;

     class OrmLifecycleListener extends AbstractListener
     {
         public function prePersist(LifecycleEventArgs $event)
         {
             $object = $event->getEntity();
             if ($this->isReferenceable($object)) {
                 $this->objectAdapterManager->persistReference($object);
             }
         }

         public function postLoad(LifecycleEventArgs $event)
         {
             $object = $event->getObject();
             if ($this->isReferenceable($object)) {
                 $this->objectAdapterManager->findReference($object);
             }
         }

         public function preRemove(LifecycleEventArgs $event)
         {
             $object = $event->getObject();
             if ($this->isReferenceable($object)) {
                 $this->objectAdapterManager->removeReference($object);
             }
         }

         public function onClear(OnClearEventArgs $event)
         {
             $this->objectAdapterManager->clear();
         }

         public function preFlush(PreFlushEventArgs $event)
         {
             $this->objectAdapterManager->flushReference();
         }
     }

通用字段

这些字段是应该在两个对象上具有相同内容的字段。包括引用者和被引用者。

这里有一个简单的例子说明为什么你需要这个:想象一下,在你的后端有产品选择,比如。这个选择只显示产品的标题。由于你想将所有文本信息持久化为ProductDocument,你决定为所有与ORM一起持久化的关系数据创建一个ProductEntity,并让它通过类型reference-phpcr引用文档。当然,产品的标题是你的文档中的一个属性。当显示这个选择时,需要标题,并且需要对列表中的每个产品进行一次查询/请求。如果商店只销售3个产品,这将是微不足道的性能影响,但如果有大量产品,这将是一个巨大的性能影响。当然,这个包为引用对象执行懒加载。这意味着在加载产品实体时,只会创建一个文档的代理。但是,当获取标题时,代理会唤醒,并进行查询/请求。

这就是通用字段的原因。您可以通过映射属性来在对象和引用对象之间保持同步。这意味着提供冗余数据,但您将获得一些性能提升。您可以在引用内部执行这种映射,因为每个属性都会进行一次引用映射(顺便说一句:您可以在一个类中执行对多个Doctrine的多个引用)


    <reference-phpcr
            target-object="Document"
            referenced-by="uuid"
            inversed-by="uuid"
            name="document">
        <common-field referenced-by="title" inversed-by="title" sync-type="from-reference"/>
    </reference-phpcr>

或者用Yaml表示


    Doctrine\Tests\ORM\ODMAdapter\Mapping\Driver\Model\ReferenceMappingObject:
      referencedField:
          type: reference-phpcr
          referenced-by: uuid
          inversed-by: uuid
          target-object: Document
          common-fields:
              - {referenced-by: title, inversed-by: title, sync-type: from-reference}

或者用xml表示

    /**
     * @ODMAdapter\ReferencePhpcr(
     *  referencedBy="uuid",
     *  inversedBy="uuid",
     *  targetObject="Document",
     *  commonFields={
     *      @ODMAdapter\CommonField(referencedBy="docName", inversedBy="entityName", syncType="from-reference")
     *  }
     * )
     */
    public $referencedField;

您可以为每个引用执行多个通用字段映射。只需将保持同步的字段设置为以下属性的值

  • referenced-by -> 被引用对象的字段
  • inversed-by -> 引用对象的字段
  • sync-type -> 同步值的方式,可能的值是from-reference(默认)和to-reference