19

SonataMediaBundle を別のエンティティ (関係 ManyToMany を持つ製品) に関連付けようとしています。

スキーマと関係は適切に作成されています。

ただし、新しい製品を編集または作成するときは、メディア ライブラリからメディア ファイルを検索できるボタンと、新しいファイルをアップロードするボタンを追加しようとします。

Admin\ProductAdmin::configureFormFieldsリレーション OneToMany の場合、これは以下を追加することで簡単に実行できます。

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

したがって、SonataMediaBundle のギャラリーで既に使用されているものと同じ 3 つのアイコンを取得します (ライブラリから追加アップロード削除) 。

しかし、関係 ManyToMany では、それは不可能です! メディアを選択するたびに、前のメディアが置き換えられるからです。そのため、複数のメディア タイプを選択することはできません。

The Galleryと同じ使い方を考えました( galleryHasMedia)

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

しかし、それは本当に複雑です。ManyToMany リレーションを介して別のエンティティで複数のメディア ファイルを選択またはアップロードするにはどうすればよいですか?

4

2 に答える 2

20

私はあなたと同じ問題を抱えていましたが、私はそれを理解しました。

まず、多対多の関係ではなく、1 対多/多対 1 の関係 (中間エンティティを使用) を選択することをお勧めします。なんで?これにより、列などの追加の列が可能になるためpositionです。このようにして、画像を好きなように並べ替えることができます。多対多の関係では、リンク テーブルには 2 つの列しかありません。関連付けられたテーブルの ID です。

Doctrineのドキュメントから:

(...) 追加の属性をアソシエーションに関連付けたい場合がよくあります。その場合、アソシエーション クラスを導入します。その結果、直接的な多対多の関連付けはなくなり、3 つの参加クラス間の 1 対多/多対 1 の関連付けに置き換えられます。

そこで、これを製品マッピング ファイルに追加しました: (ご覧のとおり、構成ファイル形式として 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) を使用して、対応するエンティティ (ProductおよびProductImage) を作成/更新しました。

次に、管理クラスを作成/更新しました。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 を使用しているので、images1 対多の関係でカスケード プロパティを追加しました。

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

それでうまくいきました(またはそう思った)がproduct_id、データベースの が に設定されていることに気付きましたNULL。クラスにprePersist()andpreUpdate()メソッドを追加することでこれを解決しました。ProductAdmin

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

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

...そして、エンティティのaddImages()メソッドに1行追加しました:Product

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

    return $this;
}

これは私にとってはうまくいきました。今では、製品への/からの画像の追加、変更、並べ替え、削除などを行うことができます。

于 2014-02-25T10:14:16.063 に答える
4

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)))
于 2014-02-18T11:04:33.373 に答える