Custom dynamic Doctrine database objects in Symfony 2

What I'm trying to achieve

  • Users will be able to customize Doctrine objects through an HTML form on a website.
  • Users will be able to define new entities, as well as add and remove fields for existing objects. (Similar to Drupal Content Types )
  • Doctrine objects will receive dynamic properties based on the configuration that the user has provided through the web interface.
  • Or one DB table per Doctrine object will dynamically change when the configuration of the object is changed; Or there may be several tables used for one object (each new field of the object will receive its own table).

Done so far

I studied this over the past few days without much success, but I came across this answer , which seems to be very related to what I'm trying to achieve.

I registered and added a listener loadClassMetadata that displays the foo field:

// 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, for me there is no way to know what properties users will define for their custom objects. If I remove the foo property from the CustomNode class, the ReflectionClass that I get from ClassMetadata will naturally not include the foo property, so I get the following exception whenever mapField () is executed in the MappingListener:

 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 custom dynamic Doctrine objects?
  • Am I on the right track with my approach? If not, can you suggest an alternative?
  • How can I have really dynamic class properties? Or should I generate new PHP classes for the Doctrine object each time users change the configuration of an entity?
+7
php symfony doctrine2
source share
1 answer

Is it possible to have fully custom dynamic Doctrine objects?

Doctrine generates proxy classes for your objects. This means that the doctrine generates PHP code with a class that extends your Entity class and redefines methods - puts some kind of user logic, and then calls the parent method.

So, I think the only way to do this really is to create PHP code for entities in your code. That is, every time an object is created on your website, you must generate a PHP file with this object, and then perform the migration.

Am I on the right track with my approach? If not, can you suggest an alternative?

I donโ€™t think you should use Doctrine ORM at all in this case, at least the way you are trying to do it.

Typically, ORM is used to simplify / more manage programming. That is, you can establish relationships, use lazy loading, a unit of work (change the properties of an object, and then just hide it), etc. If your entities are dynamically generated, what functions will you use at all? The developer will not write code for these objects, because, as you said, there is no way to find out which fields he will have.

You have not provided a specific use case - why do you want to do this in the first place. But I believe that this could be done in a simpler way.

If users can store any structure at all, should MySQL be used at all? In such cases, ElasticSearch or similar solutions can be much better.

How do I get the really dynamic properties of a class? Or should I generate new Doctrine PHP object classes every time users change the configuration of an entity?

As I said, yes. If you do not want to redefine or replace any Doctrine code, but I think it can be a lot (proxy classes, etc.).

0
source share

All Articles