如何在奏鸣曲中保存一对多关系?
Posted
技术标签:
【中文标题】如何在奏鸣曲中保存一对多关系?【英文标题】:How to save One To Many relations in Sonata? 【发布时间】:2019-06-01 15:48:39 【问题描述】:我在 Symfony4 和 Sonata Admin 中遇到问题。
我有 3 个实体:订单、产品和订单产品。 他们在这里:
订单:
class Orders
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="datetime")
*/
private $dateAdd;
/**
* @ORM\Column(type="datetime")
*/
private $dateUpd;
/**
* @ORM\Column(type="date")
*/
private $deliveryDate;
/**
* @ORM\Column(type="string", length=255)
*/
private $internalReference;
/**
* @ORM\Column(type="string", length=255)
*/
private $deliveryContactName;
/**
* @ORM\Column(type="string", length=15)
*/
private $deliveryContactPhone;
/**
* @ORM\Column(type="string", length=255)
*/
private $deliveryAddress1;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $deliveryAddress2;
/**
* @ORM\Column(type="string", length=10)
*/
private $deliveryPostalCode;
/**
* @ORM\Column(type="string", length=255)
*/
private $deliveryCountry;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $deliveryCompany;
/**
* @ORM\Column(type="integer")
*/
private $status;
/**
* @ORM\Column(type="text", nullable=true)
*/
private $comment;
/**
* @ORM\Column(type="string", length=255)
*/
private $deliveryCity;
/**
* @ORM\OneToMany(targetEntity="App\Entity\OrdersProduct", mappedBy="orders")
*/
private $product;
public function __construct()
$this->product = new ArrayCollection();
public function getId(): ?int
return $this->id;
public function getDateAdd(): ?\DateTimeInterface
return $this->dateAdd;
public function setDateAdd(\DateTimeInterface $dateAdd): self
$this->dateAdd = $dateAdd;
return $this;
public function getDateUpd(): ?\DateTimeInterface
return $this->dateUpd;
public function setDateUpd(\DateTimeInterface $dateUpd): self
$this->dateUpd = $dateUpd;
return $this;
public function getDeliveryDate(): ?\DateTimeInterface
return $this->deliveryDate;
public function setDeliveryDate(\DateTimeInterface $deliveryDate): self
$this->deliveryDate = $deliveryDate;
return $this;
public function getInternalReference(): ?string
return $this->internalReference;
public function setInternalReference(?string $internalReference): self
$this->internalReference = $internalReference;
return $this;
public function getDeliveryContactName(): ?string
return $this->deliveryContactName;
public function setDeliveryContactName(string $deliveryContactName): self
$this->deliveryContactName = $deliveryContactName;
return $this;
public function getDeliveryContactPhone(): ?string
return $this->deliveryContactPhone;
public function setDeliveryContactPhone(string $deliveryContactPhone): self
$this->deliveryContactPhone = $deliveryContactPhone;
return $this;
public function getDeliveryAddress1(): ?string
return $this->deliveryAddress1;
public function setDeliveryAddress1(string $deliveryAddress1): self
$this->deliveryAddress1 = $deliveryAddress1;
return $this;
public function getDeliveryAddress2(): ?string
return $this->deliveryAddress2;
public function setDeliveryAddress2(?string $deliveryAddress2): self
$this->deliveryAddress2 = $deliveryAddress2;
return $this;
public function getDeliveryPostalCode(): ?string
return $this->deliveryPostalCode;
public function setDeliveryPostalCode(string $deliveryPostalCode): self
$this->deliveryPostalCode = $deliveryPostalCode;
return $this;
public function getDeliveryCountry(): ?string
return $this->deliveryCountry;
public function setDeliveryCountry(string $deliveryCountry): self
$this->deliveryCountry = $deliveryCountry;
return $this;
public function getDeliveryCompany(): ?string
return $this->deliveryCompany;
public function setDeliveryCompany(?string $deliveryCompany): self
$this->deliveryCompany = $deliveryCompany;
return $this;
public function getStatus(): ?int
return $this->status;
public function setStatus(int $status): self
$this->status = $status;
return $this;
public function getComment(): ?string
return $this->comment;
public function setComment(?string $comment): self
$this->comment = $comment;
return $this;
public function getDeliveryCity(): ?string
return $this->deliveryCity;
public function setDeliveryCity(string $deliveryCity): self
$this->deliveryCity = $deliveryCity;
return $this;
public function __toString()
if ($this->id)
return $this->id." -".$this->internalReference;
else
return "";
/**
* @return Collection|OrdersProduct[]
*/
public function getProduct(): Collection
return $this->product;
public function addProduct(OrdersProduct $product): self
if (!$this->product->contains($product))
$this->product[] = $product;
$product->setOrders($this);
return $this;
public function removeProduct(OrdersProduct $product): self
if ($this->product->contains($product))
$this->product->removeElement($product);
// set the owning side to null (unless already changed)
if ($product->getOrders() === $this)
$product->setOrders(null);
return $this;
产品:
class Product
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
/**
* @ORM\Column(type="float")
*/
private $priceWT;
/**
* @ORM\Column(type="float")
*/
private $vat;
/**
* @ORM\Column(type="datetime")
*/
private $dateAdd;
/**
* @ORM\Column(type="datetime")
*/
private $dateUpd;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Category", inversedBy="products")
* @ORM\JoinColumn(nullable=false)
*/
private $category;
/**
* @ORM\Column(type="boolean")
*/
private $isDeleted;
public function getId(): ?int
return $this->id;
public function getName(): ?string
return $this->name;
public function setName(string $name): self
$this->name = $name;
return $this;
public function getPriceWT(): ?float
return $this->priceWT;
public function setPriceWT(float $priceWT): self
$this->priceWT = $priceWT;
return $this;
public function getVat(): ?float
return $this->vat;
public function setVat(float $vat): self
$this->vat = $vat;
return $this;
public function getDateAdd(): ?\DateTimeInterface
return $this->dateAdd;
public function setDateAdd(\DateTimeInterface $dateAdd): self
$this->dateAdd = $dateAdd;
return $this;
public function getDateUpd(): ?\DateTimeInterface
return $this->dateUpd;
public function setDateUpd(\DateTimeInterface $dateUpd): self
$this->dateUpd = $dateUpd;
return $this;
public function getCategory(): ?Category
return $this->category;
public function setCategory(?Category $category): self
$this->category = $category;
return $this;
public function getIsDeleted(): ?bool
return $this->isDeleted;
public function setIsDeleted(bool $isDeleted): self
$this->isDeleted = $isDeleted;
return $this;
public function __toString()
if ($this->name)
return $this->name;
else
return "Nouveau Produit";
public function calculatePriceTI()
return $this->priceWT * (1 + $this->vat);
订单产品:
class OrdersProduct
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Orders", inversedBy="product")
* @ORM\JoinColumn(nullable=false)
*/
private $orders;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Product")
* @ORM\JoinColumn(nullable=false)
*/
private $product;
/**
* @ORM\Column(type="integer")
*/
private $quantity;
/**
* @ORM\Column(type="float")
*/
private $priceWT;
public function getId(): ?int
return $this->id;
public function getOrders(): ?Orders
return $this->orders;
public function setOrders(?Orders $orders): self
$this->orders = $orders;
return $this;
public function getProduct(): ?Product
return $this->product;
public function setProduct(?Product $product): self
$this->product = $product;
return $this;
public function getQuantity(): ?int
return $this->quantity;
public function setQuantity(int $quantity): self
$this->quantity = $quantity;
return $this;
public function getPriceWT(): ?float
return $this->priceWT;
public function setPriceWT(float $priceWT): self
$this->priceWT = $priceWT;
return $this;
public function __toString()
if($this->id)
return $this->getOrders()->getId()." - ".$this->getProduct()->getName();
else
return "";
这里是订单管理员:
class OrdersAdmin extends AbstractAdmin
protected function configureFormFields(FormMapper $formMapper)
$formMapper->with('label.orders.group1', [
'class' => 'col-md-6'
])
->add('internalReference', TextType::class, [
'label' => 'label.orders.internalReference',
'required' => true
])
->add('deliveryDate', DateType::class, [
'label' => 'label.orders.deliveryDate'
])
->add('comment', TextareaType::class, [
'label' => 'label.orders.comment',
'required' => false
])
->add('deliveryContactName', TextType::class, [
'label' => 'label.orders.deliveryContactName'
])
->add('deliveryContactPhone', TextType::class, [
'label' => 'label.orders.deliveryContactPhone'
])
->add('status', ChoiceType::class, [
'label' => 'label.orders.status',
'choices' => array(
'label.orders.statuses.pending' => 1,
'label.orders.statuses.confirmed' => 2,
'label.orders.statuses.sent' => 3,
'label.orders.statuses.cancel' => 4,
)
])
->end();
$formMapper->with('label.orders.group2', [
'class' => 'col-md-6'
])
->add('deliveryCompany', TextType::class, [
'label' => 'label.orders.deliveryCompany',
'required' => false
])
->add('deliveryAddress1', TextType::class, [
'label' => 'label.orders.deliveryAddress1'
])
->add('deliveryAddress2', TextType::class, [
'label' => 'label.orders.deliveryAddress2',
'required' => false
])
->add('deliveryPostalCode', TextType::class, [
'label' => 'label.orders.deliveryPostalCode'
])
->add('deliveryCity', TextType::class, [
'label' => 'label.orders.deliveryCity'
])
->add('deliveryCountry', TextType::class, [
'label' => 'label.orders.deliveryCountry'
])
->end();
if ($this->isCurrentRoute('edit', 'admin.orders'))
$formMapper->add('product', OrdersProductType::class, array(
'order' => $this->getSubject(),
)
);
protected function configureDatagridFilters(DatagridMapper $filter)
$filter->add('internalReference')
->add('deliveryCompany');
protected function configureListFields(ListMapper $list)
$list->addIdentifier('id');
$list->add('dateAdd', 'date', [
'label' => 'label.orders.dateAdd'
]);
public function prePersist($orders)
$orders->setdateAdd(new \DateTime());
$orders->setDateUpd(new \DateTime());
public function preUpdate($orders)
$orders->setDateUpd(new \DateTime());
还有 OrdersProductType :
class OrdersProductType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options)
$builder->add('product', EntityType::class, array(
'class' => Product::class,
'multiple' => false,
'expanded' => false,
))
->add('quantity')
->add('priceWT')
->add('orders', HiddenType::class, array(
'data' => $options['order']
));
public function configureOptions(OptionsResolver $resolver)
$resolver->setRequired(array('order'));
我尝试将 CollectionType::class 与 OrdersProductAdmin 一起使用,但无法保存 OrdersProduct,因为我不知道如何将 Orders id 传递给嵌入式表单。所以,我做了一个自定义表单类型,但是:
当我提交表单时,我收到错误:
Expected value of type "App\Entity\OrdersProduct" for association field "App\Entity\Orders#$product", got "Proxies\__CG__\App\Entity\Product" instead.
如果我在 preupdate 函数中转储 $orders 变量,我有:
OrdersAdmin.php on line 121:
OrdersProduct #1405 ▶
OrdersAdmin.php on line 121:
OrdersProduct #1419 ▶
OrdersAdmin.php on line 121:
Product #1420 ▶
OrdersAdmin.php on line 121:
"33"
OrdersAdmin.php on line 121:
"12"
OrdersAdmin.php on line 121:
"1 -SG-000251 wonder"
前 2 个 OrdersProduct 是正确的(它们在我的数据库中)。但是最后 4 项是不正确的!它应该是 OrdersProduct,带有产品、数量、价格和订单。
感谢您的帮助。
最好的
【问题讨论】:
【参考方案1】:我找到了(部分,因为我现在有一个表单问题!)解决方案!
代码如下:
订单类:
/**
* @ORM\Entity(repositoryClass="App\Repository\OrdersRepository")
*/
class Orders
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="datetime")
*/
private $dateAdd;
/**
* @ORM\Column(type="datetime")
*/
private $dateUpd;
/**
* @ORM\Column(type="date")
*/
private $deliveryDate;
/**
* @ORM\Column(type="string", length=255)
*/
private $internalReference;
/**
* @ORM\Column(type="string", length=255)
*/
private $deliveryContactName;
/**
* @ORM\Column(type="string", length=15)
*/
private $deliveryContactPhone;
/**
* @ORM\Column(type="string", length=255)
*/
private $deliveryAddress1;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $deliveryAddress2;
/**
* @ORM\Column(type="string", length=10)
*/
private $deliveryPostalCode;
/**
* @ORM\Column(type="string", length=255)
*/
private $deliveryCountry;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $deliveryCompany;
/**
* @ORM\Column(type="integer")
*/
private $status;
/**
* @ORM\Column(type="text", nullable=true)
*/
private $comment;
/**
* @ORM\Column(type="string", length=255)
*/
private $deliveryCity;
/**
* @ORM\OneToMany(targetEntity="App\Entity\OrdersProduct", cascade="persist", mappedBy="orders")
*/
private $product;
public function __construct()
$this->product = new ArrayCollection();
public function getId(): ?int
return $this->id;
public function getDateAdd(): ?\DateTimeInterface
return $this->dateAdd;
public function setDateAdd(\DateTimeInterface $dateAdd): self
$this->dateAdd = $dateAdd;
return $this;
public function getDateUpd(): ?\DateTimeInterface
return $this->dateUpd;
public function setDateUpd(\DateTimeInterface $dateUpd): self
$this->dateUpd = $dateUpd;
return $this;
public function getDeliveryDate(): ?\DateTimeInterface
return $this->deliveryDate;
public function setDeliveryDate(\DateTimeInterface $deliveryDate): self
$this->deliveryDate = $deliveryDate;
return $this;
public function getInternalReference(): ?string
return $this->internalReference;
public function setInternalReference(?string $internalReference): self
$this->internalReference = $internalReference;
return $this;
public function getDeliveryContactName(): ?string
return $this->deliveryContactName;
public function setDeliveryContactName(string $deliveryContactName): self
$this->deliveryContactName = $deliveryContactName;
return $this;
public function getDeliveryContactPhone(): ?string
return $this->deliveryContactPhone;
public function setDeliveryContactPhone(string $deliveryContactPhone): self
$this->deliveryContactPhone = $deliveryContactPhone;
return $this;
public function getDeliveryAddress1(): ?string
return $this->deliveryAddress1;
public function setDeliveryAddress1(string $deliveryAddress1): self
$this->deliveryAddress1 = $deliveryAddress1;
return $this;
public function getDeliveryAddress2(): ?string
return $this->deliveryAddress2;
public function setDeliveryAddress2(?string $deliveryAddress2): self
$this->deliveryAddress2 = $deliveryAddress2;
return $this;
public function getDeliveryPostalCode(): ?string
return $this->deliveryPostalCode;
public function setDeliveryPostalCode(string $deliveryPostalCode): self
$this->deliveryPostalCode = $deliveryPostalCode;
return $this;
public function getDeliveryCountry(): ?string
return $this->deliveryCountry;
public function setDeliveryCountry(string $deliveryCountry): self
$this->deliveryCountry = $deliveryCountry;
return $this;
public function getDeliveryCompany(): ?string
return $this->deliveryCompany;
public function setDeliveryCompany(?string $deliveryCompany): self
$this->deliveryCompany = $deliveryCompany;
return $this;
public function getStatus(): ?int
return $this->status;
public function setStatus(int $status): self
$this->status = $status;
return $this;
public function getComment(): ?string
return $this->comment;
public function setComment(?string $comment): self
$this->comment = $comment;
return $this;
public function getDeliveryCity(): ?string
return $this->deliveryCity;
public function setDeliveryCity(string $deliveryCity): self
$this->deliveryCity = $deliveryCity;
return $this;
public function __toString()
if ($this->id)
return $this->id." -".$this->internalReference;
else
return "";
/**
* @return Collection|OrdersProduct[]
*/
public function getProduct(): Collection
return $this->product;
public function addProduct(OrdersProduct $product): self
if (!$this->product->contains($product))
$this->product[] = $product;
$product->setOrders($this);
return $this;
public function removeProduct(OrdersProduct $product): self
if ($this->product->contains($product))
$this->product->removeElement($product);
// set the owning side to null (unless already changed)
if ($product->getOrders() === $this)
$product->setOrders(null);
return $this;
public function setProduct($products)
$this->product = $products;
foreach ($products as $product)
$product->setOrders($this);
OrdersProduct 类:
/**
* @ORM\Entity(repositoryClass="App\Repository\OrdersProductRepository")
*/
class OrdersProduct
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Orders", inversedBy="product")
* @ORM\JoinColumn(nullable=false)
*/
private $orders;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Product")
* @ORM\JoinColumn(nullable=false)
*/
private $product;
/**
* @ORM\Column(type="integer")
*/
private $quantity;
/**
* @ORM\Column(type="float")
*/
private $priceWT;
public function getId(): ?int
return $this->id;
public function getOrders(): ?Orders
return $this->orders;
public function setOrders(?Orders $orders): self
$this->orders = $orders;
return $this;
public function getProduct(): ?Product
return $this->product;
public function setProduct(?Product $product): self
$this->product = $product;
return $this;
public function getQuantity(): ?int
return $this->quantity;
public function setQuantity(int $quantity): self
$this->quantity = $quantity;
return $this;
public function getPriceWT(): ?float
return $this->priceWT;
public function setPriceWT(float $priceWT): self
$this->priceWT = $priceWT;
return $this;
public function __toString()
if($this->id)
return $this->getOrders()->getId()." - ".$this->getProduct()->getName();
else
return "";
订单管理员:
class OrdersAdmin extends AbstractAdmin
protected function configureFormFields(FormMapper $formMapper)
$formMapper->with('label.orders.group1', [
'class' => 'col-md-6'
])
->add('internalReference', TextType::class, [
'label' => 'label.orders.internalReference',
'required' => true
])
->add('deliveryDate', DateType::class, [
'label' => 'label.orders.deliveryDate'
])
->add('comment', TextareaType::class, [
'label' => 'label.orders.comment',
'required' => false
])
->add('deliveryContactName', TextType::class, [
'label' => 'label.orders.deliveryContactName'
])
->add('deliveryContactPhone', TextType::class, [
'label' => 'label.orders.deliveryContactPhone'
])
->add('status', ChoiceType::class, [
'label' => 'label.orders.status',
'choices' => array(
'label.orders.statuses.pending' => 1,
'label.orders.statuses.confirmed' => 2,
'label.orders.statuses.sent' => 3,
'label.orders.statuses.cancel' => 4,
)
])
->end();
$formMapper->with('label.orders.group2', [
'class' => 'col-md-6'
])
->add('deliveryCompany', TextType::class, [
'label' => 'label.orders.deliveryCompany',
'required' => false
])
->add('deliveryAddress1', TextType::class, [
'label' => 'label.orders.deliveryAddress1'
])
->add('deliveryAddress2', TextType::class, [
'label' => 'label.orders.deliveryAddress2',
'required' => false
])
->add('deliveryPostalCode', TextType::class, [
'label' => 'label.orders.deliveryPostalCode'
])
->add('deliveryCity', TextType::class, [
'label' => 'label.orders.deliveryCity'
])
->add('deliveryCountry', TextType::class, [
'label' => 'label.orders.deliveryCountry'
])
->end();
if ($this->isCurrentRoute('edit', 'admin.orders'))
$formMapper->add('product', CollectionType::class, array(
'by_reference' => false,
),
array(
'edit' => 'inline',
'inline' => 'inline'
));
protected function configureDatagridFilters(DatagridMapper $filter)
$filter->add('internalReference')
->add('deliveryCompany');
protected function configureListFields(ListMapper $list)
$list->addIdentifier('id');
$list->add('dateAdd', 'date', [
'label' => 'label.orders.dateAdd'
]);
public function prePersist($orders)
$orders->setdateAdd(new \DateTime());
$orders->setDateUpd(new \DateTime());
public function preUpdate($orders)
$orders->setDateUpd(new \DateTime());
$orders->setProduct($orders->getProduct());
OrdersProductAdmin:
class OrdersProductAdmin extends AbstractAdmin
protected function configureFormFields(FormMapper $formMapper)
$formMapper->add('product', EntityType::class, [
'class'=> 'App\Entity\Product',
'choice_label' => 'name'
])
->add('quantity')
->add('priceWT')
->add('orders', EntityType::class, [
'class' => Orders::class,
'data' => $this->getRoot()->getSubject()
]);
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
protected function configureListFields(ListMapper $listMapper)
public function prePersist($objects)
//$objects->setOrders($this->getRoot()->getSubject());
//dd($objects);
OrdersProduct 表单显示良好(嵌入在其他表单中)。我可以在 OrdersProduct 表单中获取 Orders->id。
现在,我有另一个问题:表单不刷新并抛出错误 500!
【讨论】:
以上是关于如何在奏鸣曲中保存一对多关系?的主要内容,如果未能解决你的问题,请参考以下文章