【问题标题】:How to implement many-to-many relationships in Sonata Media Bundle如何在 Sonata Media Bundle 中实现多对多关系
【发布时间】:2012-07-21 17:08:54
【问题描述】:

我正在尝试将 SonataMediaBundle 与另一个实体相关联:Products 与 ManyToMany 关系。

架构和关系创建良好。

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

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

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

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

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

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

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

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

【问题讨论】:

标签: symfony sonata-admin


【解决方案1】:

您需要依赖 MediaBundle Gallery。在您的实体中,您类似于:

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

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

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

【讨论】:

    【解决方案2】:

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

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

    来自Doctrine documentation

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

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

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

    我创建了一个新的 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
    

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

    接下来,我创建/更新了管理类。 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:

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

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

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

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

    这让它工作了(或者我是这么认为的),但我注意到数据库中的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);
        }
    }
    

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

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

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

    【讨论】:

    • 漂亮的答案,您对 prePersist 和 preUpdate 函数的使用非常完美。
    猜你喜欢
    • 2012-07-05
    • 2016-09-03
    • 2020-04-10
    • 2016-04-24
    • 2016-11-28
    • 2013-06-04
    • 2016-01-05
    • 1970-01-01
    • 2012-04-05
    相关资源
    最近更新 更多