动态创建Doctrine(伪)实体?

时间:2015-01-05 21:59:26

标签: php mysql doctrine-orm doctrine

我已被抛出,可以在Doctrine'中完成。我的主管打字问题,虽然我已经能够使用外部的Mapper'对象,我想知道是否有任何方法可以伪造ORM来在Doctrine本身内完成。

基本上,我们感兴趣的是减少数据库混乱。我们有许多表包含不同类别的不同属性或项集,然后是一大堆链接表将它们绑定到其他属性或项集。例如

我们有几个表格,例如' Materials'和' PaperTypes'它描述了我们产品的各种材料和纸张选项。然后,我们将这些内容分组为“材料库”'和' PaperFamilies'分别。然后,MaterialCollection / Materials和PaperFamilies / PaperTypes之间必须有一对多的链接表。几十次重复这些类型的关系,你会看到我们的数据库开始混乱的地方。

链接表本身只不过是一些条目,包括多个记录,其中包含来自父表(集合/族)的PrimaryId和来自子表的每个父单元的唯一ID(材料/ papertypes) )。例如,链接表可以命名为MaterialCollectionsMaterials和PaperFamilyPaperTypes。

这个想法是通过使用如下的抽象3表结构来摆脱这一系列链接表:

列表(由唯一的ListId,ListName和TypeId组成) 类型(由唯一的TypeId,TypeName和EntityName组成) ListXref(由ListIds和memberId组成,它指向列表类型中指定的Entity的primaryId)

给定类型可以存在多个列表,但外部参照对是唯一的。不同的类型也可以指向同一个实体。 (例如,可能定义了多种类型的材料清单)

' ListName'将等同于上面的父TableNames,并允许消除这些关系中的两个表。因此,材料库中的记录'现在将改为TypeName" MaterialCollection"的List表中的记录。现在,将在ListXRef中指向将存在于链接表(例如MaterialCollectionsMaterials)中的记录。

如上所述,我已经获得了一个基本的映射器,可以用于创建相当基本的列表。但我想知道的是,是否有任何方法可以创建实体或类似Doctrine实体的东西来建立给定列表/列表类型与EntityName引用的表和相应的memberIds之间的抽象关系?

换句话说,如果我有一些方法可以生成具有Doctrine实体的大部分功能的东西,可以从服务管理器或类似的东西中检索出来,那将是非常好的。类似的属性/功能),如Doctrine Entity。

我尝试在实体树中添加一个包装器对象,我的映射器可以尝试检索它,它基本上是具有一些别名函数的Xref实体的继承版本,但它不能用实体管理器检索。

感谢任何帮助。

P.S。虽然目前它不是优先考虑的事项,但从长远来看,我还想通过尝试使某些列表能够指向其他列表生成的记录来真正投入工作。因此,例如,List" ProductXMaterials"类型" ProductMaterials"可能指向" MaterialCollections"的一些但不是全部结果。但是我稍后会担心这个。

1 个答案:

答案 0 :(得分:0)

好吧,Doctrine不能生成“伪实体类”,但你可以。

首先,您需要挂钩Doctrine“loadClassMetadata”事件。 在内部,您可以动态地从代码生成实体类和配置,并将它们转储到指定的目录(例如缓存中),维护命令规则,但使用自定义命名空间。例如:“AutoGeneratedNamespace \ Entities”

因此,假设您需要为名称为“TmpUser”的实体生成动态实体,并且您使用的是“yml”而不是注释

<?php
namespace Example;

use Doctrine\ORM\Event\LoadClassMetadataEventArgs;

class DoctrineEventListener
{
    /**
     * Invoked on Doctrine loadClassMetadata event
     *
     * @var Doctrine\ORM\Event\LoadClassMetadataEventArgs
     **/
    public function loadClassMetadata(LoadClassMetadataEventArgs $args)
    {
        $em             = $args->getEntityManager();
        $metadata       = $args->getClassMetadata();
        $factory        = $em->getMetadataFactory();
        $name           = 'AutoGeneratedNamespace\Entities\TmpUser';
        $tmpDirectory   = '/path/to/cache/generated-classes';

        // current class metadata is the same as the one we need. this means we already generated it
        if($metadata->getName() == $name || $factory->hasClassMetadata($name)) {
            return;
        }
        /** 
         Generate your class here and dump it into the cache directory with the name: TmpUser.php
         (If you're using "yml" instead of annotations also create the TmpUser.orm.yml configuration and dump it in the same directory)
        **/

        // create a metadata for the newly created class
        $metadata = $factory->newClassMetadataInstance($name);

        // Register metadata so doctrine knows about it
        $factory->setMetadataFor($name, $metadata);
    }

}

最后,你告诉Doctrine使用配置来查找缓存目录中的实体:(这是从Symfony文档中获取的,所以如果你不使用Symfony,它可能会有所不同,但你可以找到精确的配置在Doctrine docs中)

doctrine:
    orm:
        mappings:
            MyGeneratedEntitiesUniqueMappingsKey:
                type: yml
                dir: '/path/to/cache/generated-classes'
                is_bundle: false
                prefix: "AutoGeneratedNamespace\Entities"
                alias: GeneratedEntities