简体   繁体   English

Symfony 2中可配置的动态Doctrine数据库实体

[英]Configurable dynamic Doctrine database entities in Symfony 2

What I am trying to achieve 我想要实现的目标

  • Users would be able to configure Doctrine entities through an HTML form on a website. 用户可以通过网站上的HTML表单配置Doctrine实体。
  • Users would be able to define new entities, as well as add and delete fields for existing entities. 用户可以定义新实体,以及添加和删除现有实体的字段。 (Similar to Drupal's content types ) (类似于Drupal的内容类型
  • The Doctrine entities would get dynamic properties based on the configuration that the user supplied through the web UI. Doctrine实体将根据用户通过Web UI提供的配置获取动态属性。
  • Either the single DB table per Doctrine entity would be altered dynamically whenever an entity configuration changes; 每当实体配置发生变化时,每个Doctrine实体的单个DB表都会动态更改; Or there could be multiple tables used per single entity (each new entity field would get its own table). 或者每个实体可能有多个表使用(每个新的实体字段将获得自己的表)。

Done so far 到目前为止已完成

I have been researching this for the past few days without much success but I stumbled across this answer which seems quite related to what I am trying to achieve. 过去几天我一直在研究这个问题而没有太大的成功,但我偶然发现了这个与我想要达到的目标非常相关的答案

I have registered and added the loadClassMetadata listener which maps the field foo : 我已注册并添加了loadClassMetadata侦听器,该侦听器映射字段foo

// src/DynamicMappingTest/AdminBundle/EventListener/MappingListener.php

namespace DynamicMappingTest\AdminBundle\EventListener;

use Doctrine\ORM\Event\LoadClassMetadataEventArgs;

class MappingListener
{
    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
    {
        $classMetadata = $eventArgs->getClassMetadata();
        if ($classMetadata->getName() != 'DynamicMappingTest\\AdminBundle\\Entity\\CustomNode')
        {
            // Not the CustomNode test class. Do not alter the class metadata.
            return;
        }
        $table = $classMetadata->table;

        $oldName = $table['name'];      // ... or $classMetaData->getTableName()

        // your logic here ...

        $table['name'] = 'custom_node';

        $classMetadata->setPrimaryTable($table);

        $reflClass = $classMetadata->getReflectionClass();
        dump($reflClass);

        // ... or add a field-mapping like this

        $fieldMapping = array(
            'fieldName' => 'foo',
            'type' => 'string',
            'length' => 255
        );
        $classMetadata->mapField($fieldMapping);
    }
}

Now, this all works as long as I have the foo property declared in the DynamicMappingTest\\AdminBundle\\Entity\\CustomNode class: 现在,只要我在DynamicMappingTest \\ AdminBundle \\ Entity \\ CustomNode类中声明了foo属性,这一切都有效:

// src/DynamicMappingTest/AdminBundle/Entity/CustomNode.php

namespace DynamicMappingTest\AdminBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * CustomNode
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="DynamicMappingTest\AdminBundle\Entity\CustomNodeRepository")
 */
class CustomNode
{
    ...
    private $foo;
}

Problem 问题

However, there is no way for me to know what properties the users will define for their custom entities. 但是,我无法知道用户将为其自定义实体定义哪些属性。 If I remove the foo property from the CustomNode class, the ReflectionClass that I get from the ClassMetadata will naturally not include the foo property and so I get the following exception whenever the mapField() in MappingListener is executed: 如果我删除从CustomNodefoo的属性,则ReflectionClass,我从了ClassMetadata得到自然不会包括foo的财产,所以我得到每当执行在MappingListenerMapField可()以下异常:

ReflectionException: Property DynamicMappingTest\AdminBundle\Entity\CustomNode::$foo does not exist
in vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/RuntimeReflectionService.php at line 80

77.         */
78.        public function getAccessibleProperty($class, $property)
79.        {
80.            $reflectionProperty = new ReflectionProperty($class, $property);
81.
82.            if ($reflectionProperty->isPublic()) {
83.                $reflectionProperty = new RuntimePublicReflectionProperty($class, $property);

Questions 问题

  • Is it possible to have fully configurable dynamic Doctrine entities? 是否可以拥有完全可配置的动态Doctrine实体?
  • Am I on the right track with my approach? 我的方法是否在正确的轨道上? If not, could you suggest an alternative? 如果没有,你能建议一个替代方案吗?
  • How could I have truly dynamic class properties? 我怎么能有真正的动态类属性? Or should I be generating new Doctrine entity PHP classes whenever the users change the entity configuration? 或者,只要用户更改实体配置,我应该生成新的Doctrine实体PHP类吗?

Is it possible to have fully configurable dynamic Doctrine entities? 是否可以拥有完全可配置的动态Doctrine实体?

Doctrine generates proxy classes for you entities. Doctrine为您的实体生成代理类。 That means that doctrine generates PHP code with class, which extends your Entity class and overrides the methods - puts some custom logic and then calls the parent method. 这意味着doctrine生成带有类的PHP代码,它扩展了您的Entity类并覆盖了方法 - 放置一些自定义逻辑然后调用父方法。

So, I think that the only way to make this really happen is to generate the PHP code for entities in your code. 因此,我认为实现这一目标的唯一方法是为代码中的实体生成PHP代码。 That is, every time entity is created in your website, you should generate PHP file with that entity, then run migrations. 也就是说,每次在您的网站中创建实体时,您应该使用该实体生成PHP文件,然后运行迁移。

Am I on the right track with my approach? 我的方法是否在正确的轨道上? If not, could you suggest an alternative? 如果没有,你能建议一个替代方案吗?

I don't think that you should use Doctrine ORM at all in this case, at least in the way you're trying to do that. 在这种情况下,我认为你根本不应该使用Doctrine ORM,至少在你尝试这样做的方式。

Generally, ORM is used for easier/more manageable programming. 通常,ORM用于更容易/更易于管理的编程。 That is, you can set relations, use lazy-loading, unit of work (change entity properties and then just flush) etc. If your entities are generated dynamically, what features will you use at all? 也就是说,您可以设置关系,使用延迟加载,工作单元(更改实体属性,然后只刷新)等。如果您的实体是动态生成的,那么您将使用哪些功能? Developer will not write code for these entities, because, as you've said, there is no way to know what fields it will have. 开发人员不会为这些实体编写代码,因为正如您所说,无法知道它将具有哪些字段。

You haven't provided concrete use-case - why do you want to do that in the first place. 你还没有提供具体的用例 - 你为什么要这样做呢? But I imagine that it could be really done in some easier way. 但我想它可以通过一些更简单的方式完成。

If users can store any structure at all, should you use MySQL at all? 如果用户可以存储任何结构,你应该使用MySQL吗? ElasticSearch or similar solutions could be really much better in such cases. 在这种情况下,ElasticSearch或类似解决方案可能会更好。

How could I have truly dynamic class properties? 我怎么能有真正的动态类属性? Or should I be generating new Doctrine entity PHP classes whenever the users change the entity configuration? 或者,只要用户更改实体配置,我应该生成新的Doctrine实体PHP类吗?

As I've mentioned - yes. 正如我所说 - 是的。 Unless you would want to override or replace some of Doctrine code, but I imagine it could be lots of it (proxy classes etc.) 除非你想覆盖或替换一些Doctrine代码,但我想它可能是很多(代理类等)

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

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