Sonata Admin Bundle One-to-Many relationship not saving foreign ID

前端 未结 6 1322
粉色の甜心
粉色の甜心 2020-12-14 12:23

I have a problem with the SonataAdminBunle in combination with symfony 2.2. I have a Project entity and a ProjectImage entity and specified a One-to-Many relationship betwee

相关标签:
6条回答
  • 2020-12-14 12:52

    You ca do it directly in the preUpdate function

        public function prePersist($societate)
    {
        $this->preUpdate($societate);
    }
    
    public function preUpdate($societate)
    {
        $conturi = $societate->getConturi();
        if (count($conturi) > 0) {
            foreach ($conturi as $cont) {
                $cont->setSocietate($societate);
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-14 12:56

    Although unrelated, I'd slighty tweak your One-to-Many annotation:

    class Project
    {
        /**
         * @ORM\OneToMany(targetEntity="ProjectImage", mappedBy="project", cascade={"persist"}, orphanRemoval=true)
         * @ORM\OrderBy({"id" = "ASC"})
         */
        private $images;
    }
    

    Back on track, your annotations and Sonata Admin forms look fine, so I'm pretty sure you're missing one of those methods in your Project entity class:

    public function __construct() {
        $this->images = new \Doctrine\Common\Collections\ArrayCollection();
    }
    
    public function setImages($images)
    {
        if (count($images) > 0) {
            foreach ($images as $i) {
                $this->addImage($i);
            }
        }
    
        return $this;
    }
    
    public function addImage(\Acme\YourBundle\Entity\ProjectImage $image)
    {
        $image->setProject($this);
    
        $this->images->add($image);
    }
    
    public function removeImage(\Acme\YourBundle\Entity\ProjectImage $image)
    {
        $this->images->removeElement($image);
    }
    
    public function getImages()
    {
        return $this->Images;
    }
    

    And in your Admin class:

    public function prePersist($project)
    {
        $this->preUpdate($project);
    }
    
    public function preUpdate($project)
    {
        $project->setImages($project->getImages());
    }
    
    0 讨论(0)
  • 2020-12-14 13:01
    public function prePersist($user)
    {
        $this->preUpdate($user);
    }
    
    public function preUpdate($user)
    {
        $user->setProperties($user->getProperties());
    }
    

    This has perfectly solved the problem for me thanks !

    0 讨论(0)
  • 2020-12-14 13:03

    One way that I solved the was to manually set all inverse-side associations through a custom Sonata model manager.

    <?php
    
    namespace Sample\AdminBundle\Model;
    
    class ModelManager extends \Sonata\DoctrineORMAdminBundle\Model\ModelManager
    {
        /**
         * {@inheritdoc}
         */
        public function create($object)
        {
            try {
                $entityManager = $this->getEntityManager($object);
                $entityManager->persist($object);
                $entityManager->flush();
                $this->persistAssociations($object);
            } catch (\PDOException $e) {
                throw new ModelManagerException('', 0, $e);
            }
        }
    
        /**
         * {@inheritdoc}
         */
        public function update($object)
        {       
            try {
                $entityManager = $this->getEntityManager($object);
                $entityManager->persist($object);
                $entityManager->flush();
                $this->persistAssociations($object);
            } catch (\PDOException $e) {
                throw new ModelManagerException('', 0, $e);
            }
        }
    
        /**
         * Persist owning side associations
         */
        public function persistAssociations($object)
        {       
            $associations = $this
                ->getMetadata(get_class($object))
                ->getAssociationMappings();
    
            if ($associations) {
                $entityManager = $this->getEntityManager($object);
    
                foreach ($associations as $field => $mapping) {
                    if ($mapping['isOwningSide'] == false) {
                        if ($owningObjects = $object->{'get' . ucfirst($mapping['fieldName'])}()) {
                            foreach ($owningObjects as $owningObject) {
                                $owningObject->{'set' . ucfirst($mapping['mappedBy']) }($object);
                                $entityManager->persist($owningObject);
                            }
                            $entityManager->flush();
                        }
                    }
                }
            }
        }
    }
    

    Be sure to define this as a new service in your services.yml file:

    services:
        sample.model.manager:
            class: Sample\AdminBundle\Model\ModelManager
            arguments: [@doctrine]
    
    
        sample.admin.business:
            class: Sample\AdminBundle\Admin\BusinessAdmin
            tags:
                - { name: sonata.admin, manager_type: orm, group: "Venues", label: "Venue" }
            arguments: [~, Sample\AppBundle\Entity\Business, ~]
            calls:
                - [ setContainer, [@service_container]]
                - [ setModelManager, [@sample.model.manager]]
    
    0 讨论(0)
  • 2020-12-14 13:07

    Since some things have changed with Symfony form collection now adding the addChild() and removeChild() with the by_reference option set to false automatically persist the Collection and set the ID on the inverse side as expected.

    Here is a full working version: https://gist.github.com/webdevilopers/1a01eb8c7a8290d0b951

    protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
            ->add('childs', 'sonata_type_collection', array(
                'by_reference' => false
            ), array(
                'edit' => 'inline',
                'inline' => 'table'
            ))
        ;
    }
    

    The addChild() method must contain the setter for the parent on the child:

    public function addChild($child)
    {
        $child->setParent($this); // !important
        $this->childs[] = $child;
        return $this;
    } 
    
    0 讨论(0)
  • 2020-12-14 13:12

    the simplest solution is, and naturally replace your variable names; this works for me: 'by_reference' => false

    as follows:

    protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
            ->add('name')
            ->add('articles', EntityType::class, array(
                'class' => 'EboxoneAdminBundle:Article',
                'required' => false,
                'by_reference' => false,
                'multiple' => true,
                'expanded' => false,
            ))
            ->add('formInputs', CollectionType::class, array(
                'entry_type' => FormInputType::class,
                'allow_add' => true,
                'allow_delete' => true,
                'by_reference' => false,
            ))
        ;
    }
    
    0 讨论(0)
提交回复
热议问题