如何在Sonata Media Bundle中实现多对多关系

时间:2022-10-04 10:59:16

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

我试图将SonataMediaBundle与另一个实体联系起来:与ManyToMany有关系的产品。

The schema and relation are well created.

架构和关系很好地创建。

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.

但是,当我编辑或创建新产品时,我尝试添加一个按钮,我可以通过媒体库搜索媒体文件,然后使用按钮上传新文件。

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

对于OneToMany关系,可以通过添加以下内容在Admin \ ProductAdmin :: configureFormFields中轻松完成:

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

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

因此,我获得了与SonataMediaBundle图库中使用的相同的3个图标(从库中添加,上传和删除)

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.

但关于ManyToMany的关系是不可能的!因为每次我选择媒体时,它都会取代之前的媒体。所以我无法选择多种媒体类型。

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

我想和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?

但是,它真的很复杂。如何通过ManyToMany关系在另一个实体上选择或上传多个媒体文件?

2 个解决方案

#1


19  

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

我和你有同样的问题,但我已经弄明白了。

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.

首先,您可能希望选择一对多/多对一关系(使用中间实体)而不是多对多关系。为什么?因为这允许添加其他列,例如位置列。这样您就可以按照自己想要的方式重新排序图像。在多对多关系中,链接表只有两列:关联表的id。

From the Doctrine documentation:

从Doctrine文档中:

(...) 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.

(...)经常要将其他属性与关联相关联,在这种情况下,您需要引入关联类。因此,直接的多对多关联消失,并被3个参与类之间的一对多/多对一关联所取代。

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

所以我把它添加到我的产品映射文件中:(你可以看到我使用YAML作为我的配置文件格式)

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

And I created a new ProductImage mapping file:

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

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

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

使用命令行(php app / console doctrine:generate:entities MyBundle)我创建/更新了相应的实体(Product和ProductImage)。

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

接下来,我创建/更新了Admin类。 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')
        ;
    }

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)

不要忘记将它们都添加为服务。如果您不希望在仪表板上显示指向ProductImage表单的链接,请添加show_in_dashboard:false标记。 (如何执行此操作取决于您使用的配置格式(yaml / xml / php))

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:

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

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:

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

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

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:

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

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

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

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

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

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.

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

#2


4  

You need to rely on MediaBundle Gallery. In your entity you something like :

您需要依赖MediaBundle Gallery。在您的实体中,您可以:

/**
 * @ORM\ManyToOne(targetEntity="Application\Sonata\MediaBundle\Entity\Gallery")
 * @ORM\JoinColumn(name="image", referencedColumnName="id")
 */
private $images;

And then in your form, you'll be able to link a Gallery to your object with something like :

然后在您的表单中,您将能够使用以下内容将Gallery链接到您的对象:

->add('images', 'sonata_type_model_list', array('required' => false), array('link_parameters' => array('context' => $context)))

#1


19  

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

我和你有同样的问题,但我已经弄明白了。

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.

首先,您可能希望选择一对多/多对一关系(使用中间实体)而不是多对多关系。为什么?因为这允许添加其他列,例如位置列。这样您就可以按照自己想要的方式重新排序图像。在多对多关系中,链接表只有两列:关联表的id。

From the Doctrine documentation:

从Doctrine文档中:

(...) 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.

(...)经常要将其他属性与关联相关联,在这种情况下,您需要引入关联类。因此,直接的多对多关联消失,并被3个参与类之间的一对多/多对一关联所取代。

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

所以我把它添加到我的产品映射文件中:(你可以看到我使用YAML作为我的配置文件格式)

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

And I created a new ProductImage mapping file:

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

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

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

使用命令行(php app / console doctrine:generate:entities MyBundle)我创建/更新了相应的实体(Product和ProductImage)。

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

接下来,我创建/更新了Admin类。 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')
        ;
    }

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)

不要忘记将它们都添加为服务。如果您不希望在仪表板上显示指向ProductImage表单的链接,请添加show_in_dashboard:false标记。 (如何执行此操作取决于您使用的配置格式(yaml / xml / php))

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:

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

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:

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

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

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:

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

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

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

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

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

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.

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

#2


4  

You need to rely on MediaBundle Gallery. In your entity you something like :

您需要依赖MediaBundle Gallery。在您的实体中,您可以:

/**
 * @ORM\ManyToOne(targetEntity="Application\Sonata\MediaBundle\Entity\Gallery")
 * @ORM\JoinColumn(name="image", referencedColumnName="id")
 */
private $images;

And then in your form, you'll be able to link a Gallery to your object with something like :

然后在您的表单中,您将能够使用以下内容将Gallery链接到您的对象:

->add('images', 'sonata_type_model_list', array('required' => false), array('link_parameters' => array('context' => $context)))