Unable to persist because of uniqueness constraints for 1-n

I let users persist Brands and Cars data in a single form instead of having two different forms however I'm getting an error message "The Brand already exist in database." for those brands which already exist in Brands table. How it should work is: if the brand name already exists then don't try to persist it again because name field is marked as unique in database. How can I solve this issue?

Note: The reason why I have two extra form types is because I also have two different interfaces to collect brands and cars data individually.

CONTROLLER

public function createAction(Request $request)
{
    if ($request->getMethod() != 'POST')
    {
        return new Response('Only POST method is allowed');
    }

    $form = return $this->createForm(new BothType(), null,
            array('action' => $this->generateUrl('bothCreate')));

    $form->handleRequest($request);

    if ($form->isValid())
    {
        $brandsData = $form->get('brands')->getData();
        $carsData = $form->get('cars')->getData();

        $brands = new Brands();
        $brands->setName($brandsData->getName());

        $cars = new Cars();
        $cars->setModel($carsData->getModel());
        $cars->setBrands($brands);

        $em = $this->getDoctrine()->getManager();
        $em->persist($brands);
        $em->persist($cars);
        $em->flush();

        return $this->redirect($this->generateUrl('both'));
    }

    return $this->render('CarBrandBundle:Default:both.html.twig',
            array('page' => 'Both', 'form' => $form->createView()));
}

BOTH TYPE

class BothType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->setMethod('POST')
            ->setAction($options['action'])
            ->add('brands', new BrandsType())
            ->add('cars', new CarsType())
            ->add('button', 'submit', array('label' => 'Add'))
            ;
    }
} 

BRANDS ENTITY

/**
 * @ORM\Entity
 * @ORM\Table(name="brands", uniqueConstraints={@ORM\UniqueConstraint(columns={"name"})})
 * @UniqueEntity(fields="name", message="The Brand already exist in database.")
 * @package Car\BrandBundle\Entity
 */
class Brands
{
    protected $id;
    protected $name;

    /**
     * @ORM\OneToMany(targetEntity="Cars", mappedBy="brands")
     */
    protected $cars;

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

    public function getId() { return $this->id; }
    public function setName($name) { $this->name = $name; return $this; }
    public function getName() { return $this->name; }

    public function addCar(\Car\BrandBundle\Entity\Cars $cars)
    {
        $this->cars[] = $cars;
        return $this;
    }

    public function removeCar(\Car\BrandBundle\Entity\Cars $cars)
    {
        $this->cars->removeElement($cars);
    }

    public function getCars()
    {
        return $this->cars;
    }
}

BRANDS TYPE

class BrandsType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->setAction($options['action'])
            ->setMethod('POST')
            ->add('name', 'text', array('label' => 'Name'))
            ->add('button', 'submit', array('label' => 'Add'))
        ;
    }
}

CARS ENTITY

class Cars
{
    protected $id;
    protected $model;

    /**
     * @ORM\ManyToOne(targetEntity="Brands", inversedBy="cars")
     * @ORM\JoinColumn(name="brands_id", referencedColumnName="id", nullable=false)
     */
    protected $brands;

    public function getId() { return $this->id; }
    public function setModel($model) { $this->model = $model; return $this; }
    public function getModel() { return $this->model; }

    public function setBrands(\Car\BrandBundle\Entity\Brands $brands = null)
    {
        $this->brands = $brands;
        return $this;
    }

    public function getBrands()
    {
        return $this->brands;
    }
}

CARS TYPE

class CarsType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->setAction($options['action'])
            ->setMethod('POST')
            ->add('model', 'text', array('label' => 'Model'))
            ->add('price', 'text', array('label' => 'Price'))
            ->add('button', 'submit', array('label' => 'Add'))
        ;
    }
} 

Answers


Solved by using form model which is not mapped to database so that I could ignore uniqueness check which was causing the whole problem.

1. Create a new Model called BothModel which is not mapped to database:

class BothModel
{
    /**
     * @Assert\NotBlank(message="The Name field should not be blank")
     */
    protected $name;

    /**
     * @Assert\NotNull(message="The Origin field should not be blank")
     */
    protected $origin;

    /**
     * @Assert\NotNull(message="The Model field should not be blank")
     */
    protected $model;

    /**
     * @Assert\NotNull(message="The Price field should not be blank")
     */
    protected $price;


    public function setName($name)
    {
        $this->name = $name;
        return $this;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setOrigin($origin)
    {
        $this->origin = $origin;
        return $this;
    }

    public function getOrigin()
    {
        return $this->origin;
    }

    public function setModel($model)
    {
        $this->model = $model;
        return $this;
    }

    public function getModel()
    {
        return $this->model;
    }

    public function setPrice($price)
    {
        $this->price = $price;
        return $this;
    }

    public function getPrice()
    {
        return $this->price;
    }
} 

2. Update BothType and add form fields individually rather than initiating Brands and Cars form types.

class BothType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->setMethod('POST')
            ->setAction($options['action'])
            ->add('name', 'text', array('label' => 'Name'))
            ->add('origin', 'text', array('label' => 'Origin'))
            ->add('model', 'text', array('label' => 'Model'))
            ->add('price', 'text', array('label' => 'Price'))
            ->add('button', 'submit', array('label' => 'Add'))
            ;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array('data_class' => 'Car\BrandBundle\Form\Model\BothModel'));
    }

    public function getName()
    {
        return 'both';
    }
} 

3. Update the controller accordingly:

public function createAction(Request $request)
{
    if ($request->getMethod() != 'POST')
    {
        return new Response('Only POST method is allowed');
    }

    $form = $this->createForm(new BothType(), new BothModel(),
            array('action' => $this->generateUrl('bothCreate')));

    $form->handleRequest($request);

    if ($form->isValid())
    {
        $submission = $form->getData();

        $repo = $this->getDoctrine()->getRepository('CarBrandBundle:Brands');
        $brands = $repo->findOneBy(array('name' => $submission->getName()));

        if (! $brands)
        {
            $brands = new Brands();
            $brands->setName($submission->getName());
            $brands->setOrigin($submission->getOrigin());
        }

        $cars = new Cars();
        $cars->setModel($submission->getModel());
        $cars->setPrice($submission->getPrice());
        $cars->setBrands($brands);

        $em = $this->getDoctrine()->getManager();
        $em->persist($brands);
        $em->persist($cars);
        $em->flush();

        //return new Response('Brands ID: ' . $brands->getId() . ' - Cars ID: ' . $cars->getId());

        return $this->redirect($this->generateUrl('both'));
    }

    return $this->render('CarBrandBundle:Default:both.html.twig',
            array('page' => 'Both', 'form' => $form->createView()));
}

Need Your Help

Specifying other user owned S3 buckets in EMR job flows

amazon-web-services amazon-s3 elastic-map-reduce amazon-emr

I am trying to use an S3 bucket as input data for my Elastic Map Reduce job flow. The S3 bucket does not belong to the same account as the EMR job flow. How and where should I specify the S3 bucket

Create folder in client system

c# asp.net-3.5

My application is hosted on IIS 7.0. There is a scenario where end user save the image (from my application) into his/her machine. Now my question is can we make a default folder in end user machin...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.