由于1-n的唯一性约束,无法持久化

时间:2014-06-29 00:42:47

标签: php symfony doctrine-orm

我允许用户将BrandsCars数据保存在单个表单中,而不是使用两种不同的表单,但我收到错误消息" 品牌已存在于数据库中。 "对于Brands表中已存在的那些品牌。它应该如何工作:如果品牌名称已经存在,那么请不要再次尝试将其保留,因为name字段在数据库中被标记为唯一。我该如何解决这个问题?

注意:为什么我有两个额外的表单类型是因为我还有两个不同的界面来分别收集品牌和汽车数据。

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'))
            ;
    }
} 

品牌实体

/**
 * @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;
    }
}

品牌类型

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'))
        ;
    }
} 

1 个答案:

答案 0 :(得分:0)

使用未映射到数据库的表单模型解决,这样我就可以忽略导致整个问题的唯一性检查。

1。创建一个名为BothModel的新模型,该模型未映射到数据库:

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。更新BothType并单独添加表单字段,而不是启动品牌和汽车表单类型。

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. 相应地更新控制器:

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()));
}