bob dope
bob dope

Reputation: 479

How to get Symfony 2 with doctrine ORM to persist related entity only once

I have a 'person' entity that has a manyToOne relationship with a 'city' entity:

Here's the person's relationship mapping:

/**
* @ORM\ManyToOne(targetEntity="City", inversedBy="persons", cascade={"persist"})
*/
private $city;

and city's:

/**
* @ORM\OneToMany(targetEntity="Person", mappedBy="city")
*/
private $persons;

I use the basic Symfony 2 'person' controller generated by doctrine:generate:crud:

$entity  = new Person();
$form = $this->createForm(new PersonType(), $entity);
$form->bind($request);

if ($form->isValid()) {

        $em = $this->getDoctrine()->getManager();
        $em->persist($entity);
        $em->flush();
}

The PersonType form type instantiates a CityType

class PersonType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
        $builder
        ->add('city', new CityType())
        ->add('firstname')
        ->add('lastname')
        ->add('gender')
        ...

The CityType form type has a single text field

class CityType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
        ->add('cityname', 'text');
     }
}

When I submit the form, the Person entity is created, as well as the City entity, thanks to the cascade={"persist"}.

The problem arrises when I fill out the form with a city name that already exists in the DB, Doctrine creates another entry with the same city name.

Is there a simple way Doctrine could detect that, and use the existing city_id in the Person table?

Upvotes: 3

Views: 7928

Answers (2)

Zeljko
Zeljko

Reputation: 5158

As @vadim said, you must use datatransformer. It might be confusing at start but after ~30 minutes you will learn it. Keep in mind that around the world, you will have many cities with same name.

The best solution is this; in that text field, user would type a name like Belgrade, Montana, Usa (btw; Belgrade is capital of Serbia, just giving you an example of cities with same name). Datatransformer will read DB and find the correct city of Belgrade that you could link with.

After you do this (and it is very simple), that you could build auto-completion for that field. @artworkad suggestion is overly complicated and will bring more problems later.

Upvotes: 2

DarkLeafyGreen
DarkLeafyGreen

Reputation: 70406

One solution is, don't cascade persisting of entities. I.e.

    if ($form->isValid()) {
        $data = $form->getData();
        $em = $this->getDoctrine()->getEntityManager();

        $city = $em->getRepository('YourBundle:City')
                   ->findOneByCityname($data['cityname']);

        if($city == null){
            $city = new City();
            $city->setName($data['cityname']);
            $em->persist($city);
            $em->flush();
        }

        $entity->setCity($city);
        $em->persist($entity);
        $em->flush();
    }

Upvotes: 2

Related Questions