如何在 Sonata Media Bundle 中实现多对多关系 [英] How to implement many-to-many relationships in Sonata Media Bundle

查看:27
本文介绍了如何在 Sonata Media Bundle 中实现多对多关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将 SonataMediaBundle 与另一个实体:Products 与 ManyToMany 关联起来.

I am trying to relate SonataMediaBundle to another Entity: Products with a relation ManyToMany.

架构和关系创建良好.

但是,当我编辑或创建新产品时,我尝试添加一个按钮,我可以在其中通过媒体库搜索媒体文件,并添加一个按钮来上传新文件.

However, when I edit or create a new product, I try to add a button where I can search a media file through the media library and a button to upload a new file.

对于 OneToMany 关系,这很容易在 Admin\ProductAdmin::configureFormFields 中通过添加:

For a relation OneToMany, this is easily done in Admin\ProductAdmin::configureFormFields by adding:

->add('image', 'sonata_type_model_list', array(
                    'required' => false
                ), array(
                    'link_parameters' => array(
                        'context'  => 'default',
                        'provider' => 'sonata.media.provider.image'
                     )
                ))

所以我得到了与 SonataMediaBundle 库中已经使用的相同的 3 个图标(从库中添加上传删除)

So I get the same 3 icons as they already been used in the Gallery of SonataMediaBundle (add from library, upload and delete)

但是在 ManyToMany 关系上这是不可能的!因为每次我选择一种媒体时,它都会替换之前的媒体.所以我不能选择多种媒体类型.

BUT on the relation ManyToMany it isn't possible! Because every time I choose a media, it replaces the previous one. So I can't select multiple media types.

我考虑过使用与 The Gallery 相同的方式 (galleryHasMedia)

I thought on using the same way as The Gallery (galleryHasMedia)

->add('galleryHasMedias', 'sonata_type_collection', array(
            'by_reference' => false
        ), array(
            'edit'     => 'inline',
            'inline'   => 'table',
            'sortable' => 'position',
            'link_parameters' => array('context' => $context)
        ))

然而,它真的很复杂.如何通过多对多关系在另一个实体上选择或上传多个媒体文件?

However, it is really complex. How can I choose or upload multiple media files on another Entity through a ManyToMany Relation?

推荐答案

我和你有同样的问题,但我已经解决了.

I had the same problem as you, but I've figured it out.

首先,您可能想要选择一对多/多对一关系(使用中间实体)而不是多对多关系.为什么?因为这允许额外的列,例如 position 列.通过这种方式,您可以以任何您想要的方式重新排列图像.在多对多关系中,链接表只有两列:关联表的 id.

First of all, you might want to choose for a one-to-many/many-to-one relationship (using an intermediate entity) instead of a many-to-many relationship. Why? Because this allows for additional columns, such as a position column. This way you can reorder the images any way you want. In a many-to-many relationship, the link table only has two columns: the id's of the associated tables.

来自 Doctrine 文档:

(...) 通常您希望将附加属性与关联相关联,在这种情况下,您需要引入关联类.因此,直接的多对多关联消失了,取而代之的是 3 个参与类之间的一对多/多对一关联.

(...) frequently you want to associate additional attributes with an association, in which case you introduce an association class. Consequently, the direct many-to-many association disappears and is replaced by one-to-many/many-to-one associations between the 3 participating classes.

所以我将此添加到我的产品映射文件中:(如您所见,我使用 YAML 作为我的配置文件格式)

So I added this to my Product mapping file: (as you can see I'm using YAML as my configuration file format)

oneToMany:
    images:
        targetEntity: MyBundle\Entity\ProductImage
        mappedBy: product
        orderBy:
            position: ASC

然后我创建了一个新的 ProductImage 映射文件:

And I created a new ProductImage mapping file:

MyBundle\Entity\ProductImage:
    type: entity
    table: product_images
    id:
        id:
            type: integer
            generator: { strategy: AUTO }
    fields:
        position:
            type: integer
    manyToOne:
        product:
            targetEntity: MyBundle\Entity\Product
            inversedBy: images
        image:
            targetEntity: Application\Sonata\MediaBundle\Entity\Media

使用命令行(php app/console algorithm:generate:entities MyBundle)我创建/更新了相应的实体(ProductProductImage>).

Using the command line (php app/console doctrine:generate:entities MyBundle) I created / updated the corresponding entities (Product and ProductImage).

接下来,我创建/更新了管理类.ProductAdmin.php:

Next, I created/updated the Admin classes. ProductAdmin.php:

class ProductAdmin extends Admin
{
    protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
            // define other form fields
            ->add('images', 'sonata_type_collection', array(
                'required' => false
            ), array(
                'edit' => 'inline',
                'inline' => 'table',
                'sortable'  => 'position',
            ))
        ;
    }

ProductImageAdmin.php:

ProductImageAdmin.php:

class ProductImageAdmin extends Admin
{
    protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
            ->add('image', 'sonata_type_model_list', array(
                'required' => false
            ), array(
                'link_parameters' => array(
                    'context' => 'product_image'
                )
            ))
            ->add('position', 'hidden')
        ;
    }

不要忘记将它们都添加为服务.如果您不希望在仪表板上显示 ProductImage 表单的链接,请添加 show_in_dashboard: false 标记.(你怎么做取决于你使用的配置格式(yaml/xml/php))

Don't forget to add both of them as services. If you don't want a link to the ProductImage form to be displayed on the dashboard, add the show_in_dashboard: false tag. (how you do this depends on the configuration format (yaml/xml/php) you use)

在此之后,我的管理表单可以正常工作,但是我在尝试保存产品时仍然遇到了一些问题.我必须执行以下步骤才能解决所有问题:

After this I had the admin form working correctly, however I still had some problems trying to save products. I had to perform the following steps in order to fix all problems:

首先,我必须为 Product 实体配置级联持久化操作.同样,如何执行此操作取决于您的配置格式.我使用的是 yaml,所以在 images 一对多关系中,我添加了级联属性:

First, I had to configure cascade persist operations for the Product entity. Again, how to do this depends on your configuration format. I'm using yaml, so in the images one-to-many relationship, I added the cascade property:

oneToMany:
    images:
        targetEntity: MyBundle\Entity\ProductImage
        mappedBy: product
        orderBy:
            position: ASC
        cascade: ["persist"]

这让它工作了(或者我是这么认为的),但我注意到数据库中的 product_id 被设置为 NULL.我通过向 ProductAdmin 类添加 prePersist()preUpdate() 方法解决了这个问题:

That got it working (or so I thought), but I noticed that the product_id in the database was set to NULL. I solved this by adding prePersist() and preUpdate() methods to the ProductAdmin class:

public function prePersist($object)
{
    foreach ($object->getImages() as $image) {
        $image->setProduct($object);
    }
}

public function preUpdate($object)
{
    foreach ($object->getImages() as $image) {
        $image->setProduct($object);
    }
}

... 并在 Product 实体的 addImages() 方法中添加一行:

... and added a single line to the addImages() method of the Product entity:

public function addImage(\MyBundle\Entity\ProductImage $images)
{
    $images->setProduct($this);
    $this->images[] = $images;

    return $this;
}

这对我有用,现在我可以在我的产品中添加、更改、重新排序、删除等图像.

This worked for me, now I can add, change, reorder, delete, etc. images to/from my Products.

这篇关于如何在 Sonata Media Bundle 中实现多对多关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆