2016-01-23 7 views
11

私のモデルでは、私はRecipeエンティティとIngredientエンティティを持っています。SymfonyフォームCollectionTypeフィールドの順番

/** 
* @ORM\OneToMany(targetEntity="Ingredient", mappedBy="recipe", cascade={"remove", "persist"}, orphanRemoval=true) 
* @ORM\OrderBy({"priority" = "ASC"}) 
*/ 
private $ingredients; 

成分エンティティで:レシピエンティティでは、関係は次のように定義されて

/** 
* @ORM\ManyToOne(targetEntity="Recipe", inversedBy="ingredients") 
* @ORM\JoinColumn(name="recipe_id", referencedColumnName="id") 
*/ 
private $recipe; 

私はレシピのためにCRUDコントローラに取り組んでいると私は、ユーザーが動的成分を追加できるようにしたいです。私はまた、ユーザーがレシピで優先順位を設定するためにドラッグ・アンド・ドロップすることを望みます。私はこのためにCollectionTypeフォームフィールドを使用しています。チュートリアルとして

と、このページ:

http://symfony.com/doc/current/cookbook/form/form_collections.html

追加とレシピの上映は、これまで完璧に働いている、しかし私は、以下の記述しようとする編集/更新アクション、との問題があります:

コントローラで

、Iエンティティをロードし、このようなフォームを作成する:

public function updateAction($id, Request $request) 
    { 
     $em = $this->getDoctrine()->getManager(); 
     $recipe = $em->getRepository('AppBundle:Recipe')->find($id); 


     $form = $this->createEditForm($recipe); 
     $form->handleRequest($request); 

     ... 

    } 

先験的以来タイはDBに保存され、私は@ORM\OrderBy({"priority" = "ASC"})、最初の読み込みと材料の表示が正常に動作している。しかしながら、ユーザが成分をドラッグ・アンド・ドロップすると、優先順位値が変化する。フォーム検証エラーがあり、フォームを繰り返し表示する必要がある場合は、優先順位値が更新されても、フォーム内の成分が古い順序で表示されます。

  • A => 1
  • B => 2
  • C => 3

例えば、私は、以下の初期成分=> DBにおける優先値を有しますフォームの行は、順番に表示されます:A、B、C;ユーザ後

、私は順序を変更:

  • B => 1
  • A => 2
  • C => 3

しかしフォーム行がまだ表示されていますA、B、Cとして;

フォームはA、B、Cの順番で初期化されており、priorityの更新はArrayCollectionの要素順序を変更しないことを理解しています。しかし、私は(ほとんど)それをどのように変更するか考えていません。私がこれまで試してみました何

:すでに入力しているフォーム上にsetData()を使用することが許可されていない明らかと

$form->getData(); 
// sort in memory 
$form->setData(); 

これは、動作しません。

また、私はDataTransformerを設定して行の順序を設定しようとしましたが、新しい順序は無視されます。

私はまた、FormTypeクラスのPRE/POSTサブミットハンドラを使用してローを注文しようとしましたが、フォームは引き続き新しい注文を無視します。

(種類の)動作はこのていること最後のもの:レシピエンティティにおいて

、コントローラに、そしてメモリ内のArrayCollectionをソートsortIngredients()方法、

public function sortIngredients() 
    { 
     $sort = \Doctrine\Common\Collections\Criteria::create(); 
     $sort->orderBy(Array(
      'priority' => \Doctrine\Common\Collections\Criteria::ASC 
    )); 

     $this->ingredients = $this->ingredients->matching($sort); 

     return $this; 
    } 

を定義:

$form = $this->createEditForm($recipe); 
    $form->handleRequest($request); 

    $recipe->sortIngredients(); 

    // repeatedly create and process form with already sorted ingredients 
    $form = $this->createEditForm($recipe); 
    $form->handleRequest($request); 

    // ... do the rest of the controller stuff, flush(), etc 

これは動作しますが、フォームは2回作成され、処理されます。正直なところ、ハックのように見えます...

私はこの問題を解決するためのより良い方法を模索しています。

答えて

9

フォームタイプのfinishViewメソッドを使用する必要があります。

は、ここでのコードの例です:

public function finishView(FormView $view, FormInterface $form, array $options) 
{ 
    usort($view['photos']->children, function (FormView $a, FormView $b) { 
     /** @var Photo $objectA */ 
     $objectA = $a->vars['data']; 
     /** @var Photo $objectB */ 
     $objectB = $b->vars['data']; 

     $posA = $objectA->getSortOrder(); 
     $posB = $objectB->getSortOrder(); 

     if ($posA == $posB) { 
      return 0; 
     } 

     return ($posA < $posB) ? -1 : 1; 
    }); 
} 
+3

作品!半日を過ごしました...ありがとうございました。このメソッドについてはSymfonyのウェブサイトにはあまり書かれていません。 – Karolis

関連する問題