简体   繁体   English

原则 2:如何在 trait 中动态解析“targetEntity”和 JoinTable“name”?

[英]Doctrine 2: How to resolve “targetEntity” and JoinTable “name” dynamically in trait?

I want to create Entity which will implement following interface.我想创建将实现以下接口的实体。

<?php

namespace App\Entity\Interfaces;
#...

interface FooInterface
{
    /**
     * @param ArrayCollection|FooInterface[] $foo
     */
    public function setFoo($foo);

    /**
     * @return ArrayCollection|FooInterface[]
     */
    public function getFoo();
}

To make it simple I want to use trait to inherit properties and methods from it.为了简单起见,我想使用 trait 来继承它的属性和方法。 So finally my entities could look similar to these:所以最后我的实体可能看起来类似于这些:

<?php

namespace App\Entity\Entity;
#...

class Bar implements FooInterface
{
    use FooTrait;
}

and

<?php

namespace App\Entity\Entity;
#...

class Baz implements FooInterface
{
    use FooTrait;
}

But I don't know how to resolve targetEntity and name dynamically in @ORM annotation.但我不知道如何在@ORM注释中动态解析targetEntityname

<?php

namespace App\Entity\Traits;
#...

trait FooTrait
{
    /**
     * Many Foo has Many Foo.
     *
     * @ORM\ManyToMany(targetEntity="...")
     * @ORM\JoinTable(
     *     name="..."
     *     joinColumns={@ORM\JoinColumn(name="foo_id", referencedColumnName="id")},
     *     inverseJoinColumns={@ORM\JoinColumn(name="foo_of_id", referencedColumnName="id")}
     * )
     * @ORM\OrderBy({"id" = "ASC"})
     *
     * @var FooInterface[]|ArrayCollection
     */
    protected $foo;

    #...
}

Is the approach I chose a good one?我选择的方法是好的吗? If so how I can resolve my issue?如果是这样,我该如何解决我的问题?

I've done this before, it's pretty fun and a bit complex, but gives your application tons of flexibility.我以前做过这个,它很有趣,也有点复杂,但为您的应用程序提供了大量的灵活性。 What you are trying to do is called Dynamic Relationship Mapping.您正在尝试做的称为动态关系映射。

The detailed tutorial is here .详细教程在这里 I'll recommend you take a look at it.我会建议你看看它。 I'll just summarize the steps here:我将在这里总结一下步骤:

  1. First you need to empty the fields of ORM Annotations of the relationships you want to dynamically map.首先,您需要清空要动态映射的关系的 ORM Annotations 字段。 You cannot do this with annotations.你不能用注释来做到这一点。

  2. Second, you need to create an event subscriber/listener, listening for the loadClassMetadata event.其次,您需要创建一个事件订阅者/侦听器,监听loadClassMetadata事件。

  3. Then you need to listen just for the entities that implement the desired interface.然后您只需要监听实现所需接口的实体。 You will receive an instance of ClassMetadata on the event, that contains the ReflectionClass of your entity in-memory and a bunch of useful methods to check if implements a given interface or not, and so on, eg:您将在事件中收到ClassMetadata一个实例,其中包含您的实体在内存中的ReflectionClass和一堆有用的方法来检查是否实现了给定的接口,等等,例如:

   $metadata = $eventArgs->getMetadata();
   if (!array_key_exists(FooInterface::class,
       $metadata->getReflectionClass()->getInterfaces())) {
            return;
   }
  1. Depending of your needs, you have to call either $metadata->mapManyToMany() , ->mapManyToOne() , ->mapOneToMany() etc. It takes as argument a complex and well defined array, that contains almost the same info you will put in an annotation.根据您的需要,您必须调用$metadata->mapManyToMany()->mapManyToOne()->mapOneToMany()等。它将一个复杂且定义明确的数组作为参数,其中包含几乎相同的信息放入注释。 You can leave most of them empty to use the default.您可以将其中大部分留空以使用默认值。 What is required is that you provide the targetEntity and the fieldName (ie, the name of the property in your entity class).需要的是您提供targetEntityfieldName (即实体类中的属性名称)。

  2. Save it and register your listener as a service.保存它并将您的侦听器注册为服务。 You can debug your array configuration of step 4 with the doctrine console command orm:schema-tool:update --dump-sql , which prints out the SQL queries it would generate.您可以使用学说控制台命令orm:schema-tool:update --dump-sql调试步骤 4 的阵列配置,该命令会打印出它将生成的 SQL 查询。

SIDE NOTE: This is not an expensive operation because the classMetadata is cached by doctrine.旁注:这不是一个昂贵的操作,因为 classMetadata 是由学说缓存的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM