遵循此處的官方 Symfony 檔案時,我無法使我的邏輯正常作業:https : //symfony.com/doc/current/form/form_collections.html#allowing-tags-to-be-removed
根據示例,我需要獲取原始標簽,然后在處理表單后將它們與新標簽進行比較。
在我的例子中,我有一個Purchase物體,它可以有一個PurchaseProducts(ManyToMany)的集合。就我而言,當我更改 a 時,PurchaseProduct我需要更新已洗掉的購買的庫存。但是,無論我如何獲得原始 PurchaseProducts,在 $form->handleRequest() 之后,它們都會更新為新值,并且我會丟失有關原始值的任何資訊。
片段用邏輯形成我的控制器:
/** @var Purchase $purchase */
$purchase = $this->getDoctrine()
->getRepository(Purchase::class)
->find($id);
if (!$purchase) {
$this->addFlash('error', 'Purchase not found');
return $this->redirect($this->generateUrl('purchase_list'));
}
$originalProducts = new ArrayCollection();
foreach ($purchase->getPurchaseProducts() as $purchaseProduct) {
$originalProducts->add($purchaseProduct);
}
$form = $this->createForm(PurchaseType::class, $purchase);
if ($request->isMethod('POST')) {
dump($originalProducts); // Original entities are here
$form->handleRequest($request);
dump($originalProducts);die; // Original entities are updated with the new ones
...
// This will not work since originalProducts already has the new entities
foreach ($originalProducts as $purchaseProduct) {
if (false === $purchase->getPurchaseProducts()->contains($purchaseProduct)) {
// update stock here
}
}
我嘗試了很多選項,比如克隆、查詢資料庫等等,但是在 handleRequest 之后我總是得到相同的更新物體。為什么?
uj5u.com熱心網友回復:
行為說明
正如您所指的表單處理器的"allow_delete" => true或"allow_add" => true概念。提交表單時,副本中出現的集合中的物體屬性更改是預期行為。但是,該$originalProducts集合將不包含任何新物體 ( new PurchaseProduct())。
發生這種情況是因為 PHP 通過參考傳遞物件,即將PurchaseProduct物件傳遞給ArrayCollection. 這意味著對嵌入的表單物件所做的任何更改都應用于集合Purchase:::$purchaseProducts和$originalProducts集合,因為它們是相同的PurchaseProduct物件(按參考)。
但是,當它們在Purchase:::$purchaseProducts之后從集合中移除時$form->handleRequest($request),物件仍將存在于$originalProducts集合中。如果您的物體不包含必要的邏輯,您可以比較這兩個集合以將它們從物體管理器或物體集合中洗掉。
使用 ArrayObject 和 Foo 物件的示例:https ://3v4l.org/oLZqO#v7.4.25
Class Foo
{
private $id;
public function __construct()
{
$this->id = uniqid('', false);
}
public function setId($id)
{
$this->id = $id;
}
}
//initial state of Purchase::$purchaseProducts
$foo1 = new Foo();
$foo2 = new Foo();
$a = new ArrayObject([$foo1, $foo2]);
//Create Copy as $originalProducts
$b = new ArrayObject();
foreach ($a as $i => $foo) {
$b->offsetSet($i, $foo);
}
//form submission
$foo1->setId('Hello World');
$a->offsetUnset(1);
結果
Initial state of Copy:
ArrayObject::__set_state(array(
0 =>
Foo::__set_state(array(
'id' => '6182c24b00a21',
)),
1 =>
Foo::__set_state(array(
'id' => '6182c24b00a28',
)),
))
-----------------------
Form Submitted ID Changed in Copy:
ArrayObject::__set_state(array(
0 =>
Foo::__set_state(array(
'id' => 'Hello World',
)),
1 =>
Foo::__set_state(array(
'id' => '6182c24b00a28',
)),
))
-----------------------
Source has foo2 entity removed:
ArrayObject::__set_state(array(
0 =>
Foo::__set_state(array(
'id' => 'Hello World',
)),
))
-----------------------
Copy still contains both entities:
ArrayObject::__set_state(array(
0 =>
Foo::__set_state(array(
'id' => 'Hello World',
)),
1 =>
Foo::__set_state(array(
'id' => '6182c24b00a28',
)),
))
決議
根據您想要的結果,有多種方法可用于檢測和處理更改,例如Change Tracking Policies.
確定物體發生了什么變化的另一種方法是$em->getUnitOfWork()->getEntityChangeSet($entity)檢索提議給條令的物體的變化。
代碼建議
To ensure the request is not misinterpreted, you should always handle the form request (regardless of the request method) and verify that the form was submitted/valid. This is because the handleRequest method triggers multiple events depending on the request method.
/** @var Purchase $purchase */
$purchase = $this->getDoctrine()
->getRepository(Purchase::class)
->find($id);
if (!$purchase) {
$this->addFlash('error', 'Purchase not found');
return $this->redirect($this->generateUrl('purchase_list'));
}
$originalProducts = new ArrayCollection();
foreach ($purchase->getPurchaseProducts() as $purchaseProduct) {
$originalProducts->add($purchaseProduct);
}
$form = $this->createForm(PurchaseType::class, $purchase);
dump($originalProducts); // Original entities are here
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
dd($originalProducts); // dump die as dd() - Original entities are updated with the new ones
//...
// This will not work since originalProducts already has the new entities
foreach ($originalProducts as $purchaseProduct) {
if (false === $purchase->getPurchaseProducts()->contains($purchaseProduct)) {
//remove original from the Purchase entity
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/350069.html
