Symfony2:保存集合实体混淆

时间:2015-09-10 14:58:46

标签: symfony collections doctrine

免责声明:我是Symfony的新手。真的很难收集字段类型和简单的OnetoOne关系设置。

场景:我有一个Product实体类和一个Category实体类。我在产品上使用收集字段来创建类别项。我正在想象一个单独的类别表,其中包含名称列和相关的product_id列。我知道它通常不实用。为了论证,类别也可能是功能或其他东西,因为我只是想建立关系作为扩展的场景。最终,类别将成为一个图像字段,允许我将相关图像拉入视图。

问题:我一遍又一遍地跟着食谱文章(http://symfony.com/doc/current/cookbook/form/form_collections.html),但只是碰到了砖墙。我已经遵守了原则,但感觉我错过了一些重要的东西。我已经从javascript生成了一个protoype表单字段,并且我成功地持久保存了新产品(完整版)和新类别(仅部分版本)。相关产品ID未写入连接列。

我确定这是一个没有得到正确照顾的吸气剂/安装者的情况。我'依靠学说自动生成它们。或者问题可能是某些未指定的要求将id设置为控制器中的Category。

要遵循的代码。非常感谢,因为这已经打了好几天而且无处可去。真的很沮丧,因为很快就掌握了所有其他原则,并且在symfony中建立第一个项目真的很不错。

产品实体

<?php 

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Doctrine\Common\Collections\ArrayCollection;
use AppBundle\Entity\Category;
/**
 * Page
 *
 * @ORM\Table(name="product")
 * @ORM\Entity
 * @Vich\Uploadable
 */

class Product
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="Title", type="string", length=255)
     * @Assert\NotBlank()
     */
    private $title;

/**
 * Get id
 *
 * @return integer 
 */
public function getId()
{
    return $this->id;
}
    /**
   * @ORM\OnetoOne(targetEntity="Category", cascade={"persist"})
   */
    protected $categorys;

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

}

类别实体

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use AppBundle\Entity\Product;
/**
 * Category
 *
 * @ORM\Table(name="category")
 * @ORM\Entity
 */
class Category
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

    /**
     * @ORM\OneToOne(targetEntity="Product", cascade={"persist"})
     */
     protected $product;

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

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

        return $this;
    }

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



    /**
     * Set product
     *
     * @param \AppBundle\Entity\Product $product
     * @return Category
     */
    public function setProduct(\AppBundle\Entity\Product $product = null)
    {
        $this->product = $product;

        return $this;
    }

    /**
     * Get product
     *
     * @return \AppBundle\Entity\Product 
     */
    public function getProduct()
    {
        return $this->product;
    }
}

产品类型

<?php 
namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use AppBundle\Entity\Product;
use AppBundle\Entity\Category;

class ProductType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {

        $builder  
            ->add('title', 'text')

             ->add('categorys', 'collection', array(
              'type' => new CategoryType(),
              'allow_add' => true,
              'by_reference' => false,
              )) 

              ->add('save', 'submit', array(
                  'attr' => array('class' => 'btn btn-default'),
            ))
      ;


    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\Product',
        ));
    }

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

类别类型

<?php
namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use AppBundle\Entity\Category;


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

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\Category',
        ));
    }

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

产品控制器:新产品

  /**
   * @Route("admin/product/new", name="product_add")
   * @Security("has_role('ROLE_ADMIN')")
   */
  public function newAction(Request $request)
  {
    $product = new Product();
    $form = $this->createForm(new ProductType(), $product);

    $category = new Category();

    $form->handleRequest($request);
    if ($form->isValid()) {
        $category->getProduct($this);
        $em = $this->getDoctrine()->getManager();
        $em->persist($product);
        $em->flush();
        return $this->redirectToRoute('products_admin');
    } 

    return $this->render('Product/productAdd.html.twig', array(
        'form' => $form->createView(),
    ));        
  }

2 个答案:

答案 0 :(得分:0)

我认为在你的情况下你也不需要收藏类型。您可以为entity type更改此设置。就像我解释的那样,制作实体ManyToOne。

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Product
 *
 * @ORM\Table()
 * @ORM\Entity
 */
class Product
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

    /**
     * @var float
     *
     * @ORM\Column(name="price", type="float")
     */
    private $price;

    /**
     * @ORM\ManyToOne(targetEntity="Category")
     * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
     **/
    private $category;
}

和类别:

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Category
 *
 * @ORM\Table()
 * @ORM\Entity
 */
class Category
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

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

现在使用控制台运行一些命令:

app/console doctrine:generate:entities AppBundle
app/console doctrine:schema:update --force
app/console doctrine:generate:crud AppBundle:Product
app/console doctrine:generate:crud AppBundle:Category

如果询问您是否要生成写入操作

,请选择“是”

将__toString()方法添加到Category实体:

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

现在看看你的新控制器和路线并尝试它们。

查看所有路线:

app/console router:debug

您必须在app / config / routing.yml中使用此功能:

app:
    resource: "@AppBundle/Controller/"
    type:     annotation

最后你会得到:

- two new entities
- two new controllers
- two new form types
- eight new views

您可以从创建的代码中学到很多东西,并根据需要更改所有内容。 祝你好运

答案 1 :(得分:0)

我知道这是一个老问题,但是:

/**
   * @Route("admin/product/new", name="product_add")
   * @Security("has_role('ROLE_ADMIN')")
   */
  public function newAction(Request $request)
  {
    $product = new Product();
    $form = $this->createForm(new ProductType(), $product);

    $category = new Category();

    $form->handleRequest($request);
    if ($form->isValid()) {
        #################################
        ##$category->getProduct($this);##
        #################################
        $category->setProduct($this);
        $em = $this->getDoctrine()->getManager();
        $em->persist($product);
        $em->flush();
        return $this->redirectToRoute('products_admin');
    } 

    return $this->render('Product/productAdd.html.twig', array(
        'form' => $form->createView(),
    ));        
  }

您调用getProduct($ this)而不是setProduct($ this)