免责声明:我是Symfony的新手。真的很难处理集合字段类型和OnetoOne关系的简单设置。
场景:我有一个Product实体类和一个Category实体类。我在产品上使用一个集合字段来创建类别项。我正在描绘一个单独的类别表与名称列和相关的product_id列。我知道这并不实用。为了便于讨论,类别也可以是功能或其他东西,因为我只是想将关系建立为要扩展的场景。最终,类别将成为一个图像字段,允许我将相关图像拉入视图。
问题:我一遍又一遍地看那篇食谱文章(http://symfony.com/doc/current/cookbook/form/form_collections.html),但总是碰壁。我同意这个原则,但我觉得我错过了一些重要的东西。我有一个原型表单字段从javascript生成,我成功地持久化/保存新产品(全部)和新类别(仅部分)。相关的产品id没有写入连接列。
我确信这是getter/setter没有被正确处理的情况。我依靠理论来自动生成它们。或者问题可能是一些未指定的要求,将id设置为控制器中的Category。
接下来的代码。帮助非常感激,因为一直在敲打这个周围几天,没有得到快速。我真的很沮丧,因为我很快就掌握了所有其他原则,并且在symfony中构建了第一个项目。
产品实体<?php
namespace AppBundleEntity;
use DoctrineORMMapping as ORM;
use SymfonyComponentValidatorConstraints as Assert;
use SymfonyComponentHttpFoundationFileFile;
use VichUploaderBundleMappingAnnotation as Vich;
use DoctrineCommonCollectionsArrayCollection;
use AppBundleEntityCategory;
/**
* Page
*
* @ORMTable(name="product")
* @ORMEntity
* @VichUploadable
*/
class Product
{
/**
* @var integer
*
* @ORMColumn(name="id", type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORMColumn(name="Title", type="string", length=255)
* @AssertNotBlank()
*/
private $title;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* @ORMOnetoOne(targetEntity="Category", cascade={"persist"})
*/
protected $categorys;
public function __construct()
{
$this->categorys = new ArrayCollection();
}
}
类别实体
<?php
namespace AppBundleEntity;
use DoctrineORMMapping as ORM;
use AppBundleEntityProduct;
/**
* Category
*
* @ORMTable(name="category")
* @ORMEntity
*/
class Category
{
/**
* @var integer
*
* @ORMColumn(name="id", type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORMColumn(name="name", type="string", length=255)
*/
private $name;
/**
* @ORMOneToOne(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 AppBundleEntityProduct $product
* @return Category
*/
public function setProduct(AppBundleEntityProduct $product = null)
{
$this->product = $product;
return $this;
}
/**
* Get product
*
* @return AppBundleEntityProduct
*/
public function getProduct()
{
return $this->product;
}
}
产品类型
<?php
namespace AppBundleFormType;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolver;
use AppBundleEntityProduct;
use AppBundleEntityCategory;
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' => 'AppBundleEntityProduct',
));
}
public function getName()
{
return 'product';
}
}
类别类型
<?php
namespace AppBundleFormType;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolver;
use AppBundleEntityCategory;
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' => 'AppBundleEntityCategory',
));
}
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(),
));
}
我敢打赌,你不需要OneToOne,而是OneToMany的产品与类别的关系。因为我认为一个类别可以有多个产品,但一个产品只能有一个类别。
另一种方法是创建多多关系。在这种情况下,每个类别可以有多个产品,但每个产品也可以在多个类别中。
OneToOne不经常使用,只在特殊情况下使用。
我认为在您的情况下也不需要集合类型。您可以为实体类型更改这一点。就像我解释的那样,把实体设为ManyToOne。
namespace AppBundleEntity;
use DoctrineORMMapping as ORM;
/**
* Product
*
* @ORMTable()
* @ORMEntity
*/
class Product
{
/**
* @var integer
*
* @ORMColumn(name="id", type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORMColumn(name="description", type="string", length=64)
*/
private $description;
/**
* @var float
*
* @ORMColumn(name="price", type="float")
*/
private $price;
/**
* @ORMManyToOne(targetEntity="Category")
* @ORMJoinColumn(name="category_id", referencedColumnName="id")
**/
private $category;
}
和类别:
namespace AppBundleEntity;
use DoctrineORMMapping as ORM;
/**
* Category
*
* @ORMTable()
* @ORMEntity
*/
class Category
{
/**
* @var integer
*
* @ORMColumn(name="id", type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORMColumn(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
如果被问及是否要生成写操作,请选择YES
添加__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
您可以从创建的代码中学到很多东西,并按您的意愿更改所有内容。祝你好运
我知道这是个老问题,但是:
/**
* @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)