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

13

我想要实现什么

  • 用户可以通过网站上的HTML表单配置Doctrine实体。
  • 用户可以定义新实体,以及添加和删除现有实体的字段。(类似于Drupal的内容类型
  • Doctrine实体将根据用户通过Web UI提供的配置获取动态属性。
  • 每当实体配置更改时,单个Doctrine实体的单个DB表格将被动态更改; 或者每个单个实体可以使用多个表格(每个新实体字段将拥有自己的表格)。

目前已完成的工作

我已经进行了几天的研究,但没有取得太多成功,但我偶然发现this answer,它似乎与我正在尝试实现的内容相当相关。

I have registered and added the loadClassMetadata listener which maps the field 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:

// 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:

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?
  • 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?


你在这方面有任何进展吗?我也遇到了类似的困境,能分享一些见解吗? :) - Alex.Barylski
@Alex.Barylski 有一个类似的问题,也许可以帮助你:https://dev59.com/Npfga4cB1Zd3GeqPDfQp - A.L
我已经开发了类似于你想要实现的东西,但是我使用了标准SQL。如果你最终也使用标准SQL,那么你将始终需要使用标准SQL来选择/更新/处理你的动态实体。 - emfi
SalesForce 实现了这个概念,虽然可能没有使用 Doctrine。它允许用户创建和关联自定义对象和字段。以及在底层对象数据点上创建报表、视图/表单和仪表板。但是如上所述,ORM 不会在后端用于“生成”对象和关联,供最终用户使用。ORM 将用于开发将所有内容绑定在一起的逻辑,以便在显示分配的关联时呈现给最终用户;例如 class UserObject::$fieldsclass UserField::$dataType 等。 - Will B.
1个回答

1

是否有可能拥有完全可配置的动态Doctrine实体?

Doctrine为您的实体生成代理类。这意味着Doctrine会生成带有类的PHP代码,该类扩展了您的Entity类并覆盖了方法-放置一些自定义逻辑,然后调用父方法。

因此,我认为使这真正发生的唯一方法是在您的代码中为实体生成PHP代码。也就是说,每次在您的网站上创建实体时,都应该生成带有该实体的PHP文件,然后运行迁移。

我的方法正确吗?如果不是,您能建议一个替代方案吗?

我不认为您应该以这种方式使用Doctrine ORM,至少不是您尝试这样做的方式。

通常,ORM用于更轻松/更易管理的编程。也就是说,您可以设置关系,使用延迟加载,工作单元(更改实体属性,然后只需刷新)等。如果您的实体是动态生成的,那么您将使用哪些功能?开发人员将不会为这些实体编写代码,因为正如您所说,没有办法知道它将具有哪些字段。

您没有提供具体的用例-首先为什么要这样做。但我想象中,这可以用一种更简单的方式来完成。

如果用户可以存储任何结构,那么是否应该完全使用MySQL?在这种情况下,ElasticSearch或类似的解决方案可能会更好。
我如何拥有真正动态的类属性?或者当用户更改实体配置时,我应该生成新的Doctrine实体PHP类吗?
正如我所提到的 - 是的。除非您想要覆盖或替换一些Doctrine代码,但我想象它可能会很多(代理类等)。

一个使用案例是让客户有可能自己定义他的产品类别。在这里,他可以定义一个类应该具有哪些属性以及该属性可能具有哪些值。 我开发了这样一个东西,但我使用了标准 SQL。 - emfi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接