Comment mettre en œuvre les relations de plusieurs à plusieurs dans Sonata Media Bundle

je suis en train de relier SonataMediaBundle à une autre Entité: Produits avec une relation ManyToMany.

Le schéma et la relation sont bien créés.

Cependant, lorsque je modifier ou de créer un nouveau produit, j'essaie d'ajouter un bouton sur lequel je peux rechercher un fichier multimédia à travers les médias bibliothèque et un bouton pour télécharger un nouveau fichier.

Pour une relation OneToMany, cela se fait facilement en AdminProductAdmin::configureFormFields en ajoutant:

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

donc j'obtiens les mêmes 3 icônes comme elles ont déjà été utilisées dans la galerie de SonataMediaBundle (ajouter à la bibliothèque,télécharger et supprimer)

mais sur la relation ManyToMany ce n'est pas possible! Parce que chaque fois que je choisis un média, il remplace le précédent. Donc je ne peux pas sélectionner plusieurs types de médias.

je pensais que sur l'utilisation de la même façon que La Galerie (galleryHasMedia)

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

cependant, c'est vraiment complexe. Comment puis-je choisir ou de les télécharger plusieurs fichiers multimédia sur une autre entité à travers une relation ManyToMany?

19
demandé sur Nic Wortel 2012-07-23 16:55:27

2 réponses

j'ai eu le même problème que toi, mais j'ai trouvé.

tout d'abord, vous pourriez vouloir choisir une relation un-à-plusieurs/plusieurs-à-un (en utilisant une entité intermédiaire) au lieu d'une relation plusieurs-à-plusieurs. Pourquoi? Parce que cela permet des colonnes supplémentaires, comme un position colonne. De cette façon, vous pouvez réorganiser les images comme vous le souhaitez. Dans une relation de plusieurs à plusieurs, la table de lien n'a que deux colonnes: les id des tables associées.

à partir de Documentation sur la Doctrine:

(...) fréquemment vous voulez associer des attributs supplémentaires à une association, auquel cas vous introduisez une classe d'association. Par conséquent, l'association directe de plusieurs à plusieurs disparaît et est remplacée par des associations de un à plusieurs/plusieurs à un entre les trois classes participantes.

alors j'ai ajouté ceci à mon fichier de mappage de produit: (comme vous pouvez le voir J'utilise YAML comme fichier de configuration format)

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

Et j'ai créé un nouveau ProductImage fichier de mapping:

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

en utilisant la ligne de commande (php app/console doctrine:generate:entities MyBundle) j'ai créé / mis à jour les entités correspondantes (Product et ProductImage).

ensuite, j'ai créé/mis à jour les classes 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:

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')
        ;
    }

N'oubliez pas d'ajouter les deux comme services. Si vous ne voulez pas qu'un lien vers le formulaire ProductImage soit affiché sur le tableau de bord, ajouter show_in_dashboard: false balise. (la façon dont vous faites cela dépend du format de configuration (yaml / xml / php) que vous utilisez)

après cela, j'ai fait fonctionner correctement le formulaire d'administration, mais j'ai encore eu quelques problèmes en essayant de sauvegarder les produits. J'ai eu à effectuer les étapes suivantes afin de résoudre tous les problèmes:

tout d'abord, j'ai dû configurer les opérations de cascade persist pour l'entité produit. Encore une fois, la façon de le faire dépend de votre format de configuration. J'utilise yaml, donc dans le images relation un-à-plusieurs, j'ai ajouté la propriété cascade:

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

Que ai eu de travail (ou alors j'ai pensé), mais j'ai remarqué que le product_id dans la base de données a été définie à NULL. J'ai résolu ce problème en ajoutant prePersist() et preUpdate() méthodes à la ProductAdmin catégorie:

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

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

... et ajout d'une seule ligne à l' addImages() méthode de l' Product entité:

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

    return $this;
}

Cela a fonctionné pour moi, maintenant, je peux ajouter, modifier, réorganiser, supprimer, etc. les images vers/à partir de mes Produits.

19
répondu Nic Wortel 2016-06-22 14:53:06

vous devez compter sur MediaBundle Gallery. Dans votre entité, vous quelque chose comme :

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

et puis dans votre forme, vous serez en mesure de lier une galerie à votre objet avec quelque chose comme :

->add('images', 'sonata_type_model_list', array('required' => false), array('link_parameters' => array('context' => $context)))
4
répondu LaurentG 2014-02-18 11:04:33