我有2个实体,练习和产品,他们有一对一的关系(拥有方是Product),我有一个ExerciseFormType和一个ProductFormType。
我希望我能够同时创建练习以及与之相关的产品。
我的想法是添加exerciseFormType的构建器,'product',它的类型将是ProductFormType。问题是产品需要exercise_id,并且练习没有持久化,所以它没有。这是我到目前为止所做的(它仅适用于在练习存在时创建产品)。
<?php
/**
* exercise
*
* @ORM\Table(name="exercise")
* @ORM\Entity(repositoryClass="SchoolBundle\Repository\ExerciseRepository")
*/
class Exercise {
/**
* @var int
* @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;
/**
* @var string
* @ORM\Column(name="content", type="string", length=255)
*/
private $content;
/**
* @var string
* @ORM\Column(name="language", type="string", length=255)
*/
private $language;
/**
* @var int
* @ORM\Column(name="level", type="integer")
*/
private $level;
/**
* @var string
* @ORM\Column(name="skills_required", type="string", length=255)
*/
private $skillsRequired;
/**
* @var string
* @ORM\Column(name="skills_targetted", type="string", length=255)
*/
private $skillsTargetted;
/**
* @var string
* @ORM\Column(name="tags", type="string", length=255)
*/
private $tags;
/**
* @ORM\OneToMany(targetEntity="Session", mappedBy="exercise")
*/
private $sessions;
/**
* @ORM\OneToMany(targetEntity="ExerciseIO", mappedBy="exercise")
*/
private $exerciseIOs;
/**
* @ORM\OneToOne(targetEntity="MarketBundle\Entity\Product", mappedBy="exercise", cascade={"persist"}))
*/
private $product;
/**
* @ORM\ManyToOne(targetEntity="Professor", inversedBy="createdExercises")
* @ORM\JoinColumn(name="creator_id", referencedColumnName="id", nullable=false)
*/
private $creator;
/**
* @ORM\ManyToMany(targetEntity="Professor", mappedBy="boughtExercises")
*/
private $owners;
public function __construct(){
$this->sessions = new ArrayCollection();
$this->exerciseIOs = new ArrayCollection();
$this->owners = new ArrayCollection();
}
/**
* Get creator
* @return Professor
*/
public function getCreator(){
return $this->creator;
}
/**
* Set creator
* @param Professor $creator
* @return Exercise
*/
public function setCreator($creator){
$this->creator = $creator;
return $this;
}
/**
* Get owner
* @return ArrayCollection
*/
public function getOwners(){
return $this->owners;
}
/**
* Get product
* @return Product
*/
public function getProduct(){
return $this->product;
}
/**
* @param Product $product
* @return Exercise
*/
public function setProduct($product){
$this->product = $product;
return $this;
}
/**
* Get exerciseIOs
* @return ArrayCollection
*/
public function getExerciseIOs(){
return $this->exerciseIOs;
}
/**
* Get sessions
* @return ArrayCollection
*/
public function getSessions(){
return $this->sessions;
}
/**
* Get id
* @return int
*/
public function getId(){
return $this->id;
}
/**
* Set name
* @param string $name
* @return Exercise
*/
public function setName($name){
$this->name = $name;
return $this;
}
/**
* Get name
* @return string
*/
public function getName(){
return $this->name;
}
/**
* Set content
* @param string $content
* @return Exercise
*/
public function setContent($content){
$this->content = $content;
return $this;
}
/**
* Get content
* @return string
*/
public function getContent(){
return $this->content;
}
/**
* Set language
* @param string $language
* @return Exercise
*/
public function setLanguage($language){
$this->language = $language;
return $this;
}
/**
* Get language
* @return string
*/
public function getLanguage(){
return $this->language;
}
/**
* Set level
* @param string $level
* @return Exercise
*/
public function setLevel($level){
$this->level = $level;
return $this;
}
/**
* Get level
* @return string
*/
public function getLevel(){
return $this->level;
}
/**
* Set skillsRequired
* @param string $skillsRequired
* @return Exercise
*/
public function setSkillsRequired($skillsRequired){
$this->skillsRequired = $skillsRequired;
return $this;
}
/**
* Get skillsRequired
* @return string
*/
public function getSkillsRequired(){
return $this->skillsRequired;
}
/**
* Set skillsTargetted
* @param string $skillsTargetted
* @return Exercise
*/
public function setSkillsTargetted($skillsTargetted){
$this->skillsTargetted = $skillsTargetted;
return $this;
}
/**
* Get skillsTargetted
* @return string
*/
public function getSkillsTargetted(){
return $this->skillsTargetted;
}
/**
* Set tags
* @param string $tags
* @return Exercise
*/
public function setTags($tags){
$this->tags = $tags;
return $this;
}
/**
* Get tags
* @return string
*/
public function getTags(){
return $this->tags;
}
}
在运动中我有那个
/**
* Product
*
* @ORM\Table(name="product")
* @ORM\Entity(repositoryClass="\MarketBundle\Repository\ProductRepository")
*/
class Product {
/**
* @var int
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var bool
* @ORM\Column(name="visibility", type="boolean")
*/
private $visibility;
/**
* @var float
* @ORM\Column(name="price", type="float")
*/
private $price;
/**
* @var \DateTime
* @ORM\Column(name="publication_date", type="datetimetz")
*/
private $publicationDate;
/**
* @var \DateTime
* @ORM\Column(name="update_date", type="datetimetz", nullable=true)
*/
private $updateDate;
/**
* @ORM\OneToMany(targetEntity="ProductComment", mappedBy="product")
*/
private $productComments;
/**
* @ORM\OneToOne(targetEntity="\SchoolBundle\Entity\Exercise", inversedBy="product")
* @ORM\JoinColumn(name="exercise_id", referencedColumnName="id", nullable=false)
*/
private $exercise;
public function __construct(){
$this->productComments = new ArrayCollection();
}
/**
* Get exercise
* @return Exercise
*/
public function getExercise(){
return $this->exercise;
}
/**
* Set exercise
* @param Exercise $exercise
* @return Product
*/
public function setExercise($exercise){
$this->exercise = $exercise;
return $this;
}
/**
* Get productComments
* @return ArrayCollection
*/
public function getProductComments(){
return $this->productComments;
}
/**
* Get id
* @return int
*/
public function getId(){
return $this->id;
}
/**
* Set visibility
* @param boolean $visibility
* @return Product
*/
public function setVisibility($visibility){
$this->visibility = $visibility;
return $this;
}
/**
* Get visibility
* @return bool
*/
public function getVisibility(){
return $this->visibility;
}
/**
* Set price
* @param float $price
* @return Product
*/
public function setPrice($price){
$this->price = $price;
return $this;
}
/**
* Get price
* @return float
*/
public function getPrice(){
return $this->price;
}
/**
* Set publicationDate
* @param \DateTime $publicationDate
* @return Product
*/
public function setPublicationDate($publicationDate){
$this->publicationDate = $publicationDate;
return $this;
}
/**
* Get publicationDate
* @return \DateTime
*/
public function getPublicationDate(){
return $this->publicationDate;
}
/**
* Set updateDate
* @param \DateTime $updateDate
* @return Product
*/
public function setUpdateDate($updateDate){
$this->updateDate = $updateDate;
return $this;
}
/**
* Get updateDate
* @return \DateTime
*/
public function getUpdateDate(){
return $this->updateDate;
}
}
在产品
中public function newAction(Request $request){
$exercise = new Exercise();
$form = $this->createForm(ExerciseType::class, $exercise);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$exercise->setCreator($this->getUser());
$em = $this->getDoctrine()->getManager();
$em->persist($exercise);
$em->flush();
return $this->redirectToRoute('exercise_show', array('id' => $exercise->getId()));
}
我说它适用于现有的练习(而且没有产品)。 当我尝试同时创建两者时
必须管理传递到选择字段的实体。也许坚持他们在实体经理?
它可能来自$ builder-&gt; getData(),因为在这种情况下我只传递给了一个“new Exercice()”。这是控制器动作
{{1}}
(另外这是另一个问题,但是当我禁用一个formType时,它会被渲染,并且值会出现但是它没有提交。我实际上更喜欢hiddenFormType但我需要DateTimeFormType的格式化)
答案 0 :(得分:0)
好的,这是我用Symfony2.8做过的解决方案,我希望它可以帮到你。
/**
* @ORM\Entity
* @ORM\Table(name="picture")
*/
class Picture
{
/**
* @ORM\OneToOne(targetEntity="AppBundle\Entity\Host",
* inversedBy="pictureId"
* )
* @ORM\JoinColumn(name="avatar_host_id", referencedColumnName="id", nullable=true)
*/
private $avatarHostId;
}
/**
* @ORM\Entity
* @ORM\Table(name="host")
*/
class Host
{
/**
* @ORM\OneToOne(targetEntity="AppBundle\Entity\Picture",
* mappedBy="avatarHostId", cascade={"persist", "remove", "merge"}
* )
*/
private $pictureId;
}
class HostType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('pictureId', PictureFileType::class);
}
}
class PictureFileType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('assetFile', FileType::class, array(
'label' => 'Picture File',
'required' => false,
'validation_groups' => array('creation')
));
}
}
答案 1 :(得分:0)
首先,我建议不要使用整数作为ID。它们周围存在一些问题,包括在这种情况下您无法随意生成一个问题。我建议Uuid
s along with ramsey/uuid,它也有Doctrine mapping。
如果您遇到需要ID的情况,并且已生成Uuid
,请自行生成Uuid
。例如,在一个人为的例子中
class Order
{
/**
* @var UuidInterface
*
* @ORM\Id
* @ORM\Column(type="uuid")
* @ORM\GeneratedValue(strategy="NONE")
* @ORM\CustomIdGenerator(class=UuidGenerator::class)
*/
private $id;
...
/**
* Constructor.
*
* @param UuidInterface $id
*/
public function __construct(?UuidInterface $id = null)
{
$this->id = $id ?? Uuid::uuid4();
}
...
}
class OrderController
{
...
public function orderProductAction(): JsonResponse
{
...
// We need this ahead of time, because
// maybe this is Async and we need to
// return the order id. This happens a
// lot with commands.
$generatedId = Uuid::uuid4();
// Here it's going to use the given ID,
// if not given, the Order class will
// generate it.
$order = new Order($generatedId, ...);
// Stuff happens, persisted... maybe we
// don't have the persisted Order object...
return $this->json([
'order' => [
'id' => $generatedId->toString(),
],
]);
}
...
}
它的主要内容是在构造函数中提供生成的Uuid
(如果null
,它会交替生成它)。 不添加setter。这是一个更为复杂的例子:
public function createAction(Request $request): JsonResponse
{
$request_data = \json_decode($request->getContent(), true);
$tenant_data = $request_data['data'];
// Pre-generate our Uuid for the Tenant.
$generated_id = Uuid::uuid4();
/** @var CreateTenant $create_tenant_cmd */
$create_tenant_cmd = new CreateTenant($generated_id);
$create_tenant_cmd->setName($tenant_data['name']);
$create_tenant_cmd->setDomainName($tenant_data['domain_name']);
$create_tenant_cmd->setOwnerUsername($tenant_data['owner_username']);
$create_tenant_cmd->setOwnerPassword($tenant_data['owner_password']);
$create_tenant_cmd->setOwnerFirstName($tenant_data['owner_first_name']);
$create_tenant_cmd->setOwnerLastName($tenant_data['owner_last_name']);
$create_tenant_cmd->setOwnerEmail($tenant_data['owner_email']);
if (!$this->isGranted('perform', $create_tenant_cmd)) {
throw new AccessDeniedException('Access denied to create tenant.');
}
// Here, we should expect NO side-effects, the command
// can't return anything. So no Tenant object with
// generated Uuid...
$this->get('command_bus')->handle($create_tenant_cmd);
/* @var Serializer $serializer */
$serializer = $this->get('jms_serializer');
$serializer_context = SerializationContext::create()->setGroups([
'tenant_meta',
]);
$tenant = $this->get('app.repository.tenant')->find($generated_id);
return $this->json(\json_decode($serializer->serialize(
$tenant,
'json',
$serializer_context
)));
}
这是ID问题;您的问题的第二部分现在很容易解决,即Uuid
代替FormType
:
$form = $this->createForm(OrderProductType::class, $product, [
'product' => $product,
'generatedId' => $generatedId,
]);
class OrderProductType extends AbstractType implements DataMapperInterface
{
/** @var UuidInterface */
protected $generatedId;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->generatedId = $options['generatedId'];
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults([
'data_class' => OrderProduct::class,
])
->setRequired(['generatedId'])
;
}
public function mapFormsToData($forms, &$data)
{
$forms = iterator_to_array($forms);
$data = new OrderProduct($this->generatedId);
...
}
}
当然,如果您需要它作为字段,请将其与您选择的字段类型一起使用,而不是将其存储为变量,然后从该字段中获取它:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('product_id', HiddenType::class, [
'product_id' => $options['generatedId']->toString(),
])
...
;
}
public function mapFormsToData($forms, &$data)
{
$forms = iterator_to_array($forms);
// Note use of Uuid::fromString().
$data = new OrderProduct(Uuid::fromString(
$forms['productId']->getData()
));
...
}
这是不将交互的进程委托给委托对象(如命令)而不是生成实体的缺点之一;在你需要它之前,你需要整体构建你的对象,或者在设计中使它变得合适。它也使得断言的处理更加困难(你只得到一套,实体&#39;)。