简体   繁体   中英

How to Create Dynamic Entity Association with Doctrine2 in Symfony2

I am building a CMS, with dynamic routing, a versioning system, and multiple different content types, eg Article, Profile, etc. I have a ContentType entity that stores all the available content types that a View can be. But the data for that content type instance will be stored in a separate entity (since the fields are unique for each type of content so it can't all fit in the ViewVersion ).

Routing --> View --> ViewVersion --> Article
or
Routing --> View --> ViewVersion --> Profile

Routing A --ManyToOne--> View D
Routing B --ManyToOne--> View D
Routing C --ManyToOne--> View D

View D --> ManyToOne -> ContentType (define what type this view is)
View D --> OneToOne --> Settings

View D --OneToMany--> ViewVersion E
View D --OneToMany--> ViewVersion F
View D --OneToMany--> ViewVersion G (*published version*)

ViewVersion E --OneToOne--> Article E
ViewVersion F --OneToOne--> Article F
ViewVersion G --OneToOne--> Article G

For detailed background information about the workflow of the application (still in flux), you can see a description in my related question here , under the heading "Background of Project and Structure of Code".

Each of these content types will have different fields and functionality, so they will be defined in unique bundles and they need to exist in their own separate entities (database tables with unique fields).

My main Controller finds the View based on the Routing url, and loads the right bundle controller to assemble the page (with unique functions and template for the body area).

The Routing entity stores one or more URLs that point to a View entity.

The View entity is a basic placeholder that routes can point to, and it then points to multiple versions, and sets the id of the published version.

The ViewVersion has all the basic information for an HTML page, metadata, design shell, browser title, etc, but nothing about the content. A new ViewVersion is saved when edited by a new user or if the version hasn't been saved in 30 minutes.

There is no ContentType entity, it will be an actual entity from a bundle, eg Gutensite\\ArticleBundle\\Entity\\Article , Gutensite\\ProfileBundle\\Entity\\Profile , etc and will be linked directly to the ViewVersion based on the View->ContentType set (so we know what type of entity it is). The ContentType (eg Article) will be OneToOne back to the corresponding id of the ViewVersion, eg Article->viewVersionId (each version has one content type record). Every time a new ViewVersion is saved, the corresponding ContentType is saved as well (clone all entity associations). They are essentially one record, just split into different entities because of the dynamic relationship between a view and multiple content types.

Traditional ORM mapping won't work between ViewVersion and the dynamic ContentType, because the content could be one of several different entities in different bundles, so I can't map to a single static Article or Profile entity. This linking needs to be dynamic.

I would like to set the association so that I can easily call $viewVersion->getContent() to get the content type fields, and also use the formBuilder to load the right formType for that entity.

It's easy to associate the right FormType for the form builder:

class ViewVersionType extends AbstractType
{

    public function getName()
    {
        return 'viewVersion';
    }

public function buildForm(FormBuilderInterface $builder, array $options)
{
        // Add all the regular Fields
        $builder->add(...);

        // Add Dynamic Content Type Association
        //Get the form type for the requested content type and merge with the default view form
        $viewVersion = $builder->getData();
        $view = $viewVersion->getEntity();

        $contentPath = $view->namespace_bundle.'\\Form\\Type\\'.$view->getContentType()->getBundle().'Type';
        $builder->add('content', new $contentPath, array(
           'label' => false
        ));
    }
}

But what is the best way to add dynamic mapping between the ViewVersion and the related ContentType?

Options

I read about Resolve Target Entities but that doesn't seem like the best option, plus you have to register each bundle in the orm config which is not ideal.

I also read about Dynamic Form Modification but that's not really necessary given my solution for forms and doesn't solve the basic problem of entity mapping.

I also read about dynamic mapping via an event subscriber which seems like exactly what I need. I assume I would put the trait on the dynamic content type entity, to point BACK to the ViewVersion. Then I would se the mapping association between the two. But I still can't figure out how to access the data I need in that subscriber event, to correctly tell the ViewVersion about the Article or Profile entity. I haven't grasped the big picture of Symonfy's architecture yet, to know how everything is related, how to access the variables I need, and where to find the right documentation!

Some thoughts here that might help ( or not ):

  • The structure you are trying to achieve is similar to how Drupal manage the content using nodes, content types and node revisions. You might want to read more about how they structured it here .

  • I have a feeling that ContentType should be linked to View not ViewVersion . I can not imagine that different versions of the same view can have different content types. A view should have a certain type and different versions.

  • I can't quite get why View -> ContentType will be a OneToOne relation. I would say that there is a set of content types and each View is assigned to one ContentType so it seems more like a ManyToOne relationship.

  • I would not try to make a bundle per content type. I would say you can have a Blog bundle with different content types and views.

  • View entity can have a $content_type_id which references the id of the ContentType . Doctrine uses lazy loading and when you load the View entity, doctrine won't care what ContentType it is linked to but will be aware of the content_type_id of that View and whenever you need the linked ContentType it will run the query to fetch it and link the correct ContentType to your View .

  • I always find it best to get ideas by looking at the source code of symfony bundles and see how things are being structured.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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