0
votes

I tried to find an answer for my question but it was unsuccessful. I'm using Symfony (Ive been using it 2 months) and I have a problem when I want to make many to many relationship.

I have homes and I have services. One home can have a lot of services and one service can have a lot of homes. Everything is ok and I understand the way many to many works with the doctrine, i persisted all values before flush in my controller, but i always get this message:

An exception occurred while executing 'INSERT INTO homess_services (home_id, service_id) VALUES (?, ?)' with params [25, 7]:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '25' for key 'home_id'

My codes are (home entity):

<?php

namespace Filip\SymfonyBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Filip\SymfonyBundle\FilipSymfonyBundle;

/**
 * Home
 *
 * @ORM\Table(name="homes")
 * @ORM\Entity
 *
 *
 */
class Home
{
    /**
     * @var ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity="Service", inversedBy="homes")
     * @ORM\JoinTable(name="homess_services")
     */




       protected $services;

    public function __construct()   {
            $this->photos = new ArrayCollection();
            $this->services = new ArrayCollection();
        }

/**
     * Renders a publication as a string
     *
     * @return string
     */
    public function __toString (){
        return $this->getName();
    }

/**
     * Add services
     *
     * @param \Filip\SymfonyBundle\Entity\Service $services
     * @return Home
     */
    public function addService(\Filip\SymfonyBundle\Entity\Service $services)
    {
        $this->services[] = $services;

        return $this;
    }

    /**
     * Remove services
     *
     * @param \Filip\SymfonyBundle\Entity\Service $services
     */
    public function removeService(\Filip\SymfonyBundle\Entity\Service $services)
    {
        $this->services->removeElement($services);
    }

    /**
     * Get services
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getServices()
    {
        return $this->services;
    }

Service entity:

<?php

namespace Filip\SymfonyBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Filip\SymfonyBundle\FilipSymfonyBundle;

/**
 * Service
 *
 * @ORM\Table("services")
 * @ORM\Entity

 */
class Service
{


    /**
     * @var ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity="Home", mappedBy="services")
     */
    protected $homes;

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM

\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @var string
 *
 * @ORM\Column(name="category", type="string", length=45)
 */
private $category;

/**
 * @var string
 *
 * @ORM\Column(name="name", type="string", length=45)
 */
private $name;

/**
 * Renders a service as a string
 *
 * @return string
 */




/**
 * Get id
 *
 6

 * @return integer 
 */
public function getId()
{
    return $this->id;
}

/**
 * Set category
 *
 * @param string $category
 * @return Service
 */
public function setCategory($category)
{
    $this->category = $category;

    return $this;
}

/**
 * Get category
 *
 * @return string 
 */
public function getCategory()
{
    return $this->category;
}

/**
 * Set name
 *
 * @param string $name
 * @return Service
 */
public function setName($name)
{
    $this->name = $name;

    return $this;
}

/**
 * Get name
 *
 * @return string 
 */
public function getName()
{
    return $this->name;
}

public function __construct()
{
    $this->homes = new ArrayCollection();
}

/**
 * Add homes
 *
 * @param \Filip\SymfonyBundle\Entity\Home $homes
 * @return Service
 */
public function addHome(\Filip\SymfonyBundle\Entity\Home $homes)
{
    $this->homes[] = $homes;

    return $this;
}

/**
 * Remove homes
 *
 * @param \Filip\SymfonyBundle\Entity\Home $homes
 */
public function removeHome(\Filip\SymfonyBundle\Entity\Home $homes)
{
    $this->homes->removeElement($homes);
}

/**
 * Get homes
 *
 * @return \Doctrine\Common\Collections\Collection 
 */
public function getHomes()
{
    return $this->homes;
}
}

Form(HomeType):

<?php

namespace Filip\SymfonyBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;


class HomeType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name')
            ->add('city')
            ->add('region')
            ->add('phone')
            ->add('address')
            ->add('email')
            ->add('website')
            ->add('content')
            ->add('youtubeApi')
            ->add('premium')

            ->add('services' , 'entity' , array(
                'class'    => 'FilipSymfonyBundle:Service' ,
                'property' => 'name' ,
                'expanded' => true ,
                'multiple' => true ,
                ));
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Filip\SymfonyBundle\Entity\Home'
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'filip_symfonybundle_home';
    }
}

Home controller:

/**
     * Creates a new Home entity.
     *
     * @Route("/", name="home_create")
     * @Method("POST")
     * @Template("FilipSymfonyBundle:Home:new.html.twig")
     */
    public function createAction(Request $request)
    {
        $entity = new Home();
        $form = $this->createCreateForm($entity);
        $form->handleRequest($request);

        if ($form->isValid()) {

            $em = $this->getDoctrine()->getManager();
            $services = $entity->getServices();

            foreach($services as $service) {
                $entity->addService($service);
                $em->persist($service);
            }
            $em->persist($entity);
            $em->flush();

            return $this->redirect($this->generateUrl('home_show', array('id' => $entity->getId())));
        }

        return array(
            'entity' => $entity,
            'form'   => $form->createView(),
        );
    }

    /**
     * Creates a form to create a Home entity.
     *
     * @param Home $entity The entity
     *
     * @return \Symfony\Component\Form\Form The form
     */
    private function createCreateForm(Home $entity)
    {
        $form = $this->createForm(new HomeType(), $entity, array(
            'action' => $this->generateUrl('home_create'),
            'method' => 'POST',
        ));

        $form->add('submit', 'submit', array('label' => 'Create'));

        return $form;
    }
1

1 Answers

2
votes

in the if($form->isValid()) part you don't need to call the addService() method in the foreach loop as Symfony will do this for you on the handleRequest() call. If the Home entity is at the owning side of the ManyToMany relation you don't need to persist every Service object too. So you can try to remove the whole foreach loop too.