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