2016-01-23 16 views
11

Trong mô hình của tôi, tôi có một thực thể Công thức và thực thể Thành phần. Trong thực Recipe, mối quan hệ được định nghĩa như thế này:Thứ tự của biểu mẫu Symfony Trường CollectionType

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

trong thực thể Thành phần:

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

tôi đang làm việc trên bộ điều khiển CRUD cho các công thức và tôi muốn người dùng có thể thêm các thành phần tự động . Tôi cũng muốn người dùng kéo và thả các thành phần để đặt mức độ ưu tiên (thứ tự) trong công thức. Tôi đang sử dụng trường biểu mẫu CollectionType cho việc này.

và trang này như hướng dẫn:

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

Thêm và hiển thị của công thức đang làm việc một cách hoàn hảo cho đến nay, tuy nhiên có một vấn đề với Edit/Cập nhật hành động, mà tôi sẽ cố gắng để mô tả dưới đây:

Trong bộ điều khiển, tôi tải các thực thể và tạo ra các hình thức như thế này:

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


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

     ... 

    } 

Kể từ khi priori ty được lưu trong DB, và tôi có @ORM\OrderBy({"priority" = "ASC"}), tải ban đầu và hiển thị các thành phần hoạt động tốt. Tuy nhiên, nếu người dùng kéo và thả các thành phần xung quanh, các giá trị ưu tiên sẽ thay đổi. Trong trường hợp có lỗi xác nhận biểu mẫu và biểu mẫu cần được hiển thị nhiều lần, các thành phần bên trong biểu mẫu được hiển thị theo thứ tự cũ, mặc dù các giá trị ưu tiên được cập nhật.

Ví dụ, tôi có => giá trị ưu tiên sau Ingredient ban đầu trong DB:

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

Các hàng biểu mẫu được hiển thị theo thứ tự: A, B, C;

Sau khi người dùng thay đổi thứ tự, tôi có:

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

nhưng các hàng hình thức vẫn đang hiển thị như A, B, C;

Tôi hiểu rằng biểu mẫu đã được khởi tạo với thứ tự A, B, C và cập nhật priority không thay đổi thứ tự phần tử của ArrayCollection. Nhưng tôi có (gần như) không có ý tưởng làm thế nào để thay đổi nó.

Những gì tôi đã cố gắng cho đến nay:

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

này không hoạt động, như dường như nó không được phép sử dụng SetData() vào mẫu mà đã có đầu vào.

Tôi cũng đã cố gắng đặt Trình dịch dữ liệu để đặt hàng, nhưng biểu mẫu bỏ qua thứ tự mới.

Tôi cũng đã cố gắng sử dụng trình xử lý gửi PRE/POST trong lớp FormType để đặt hàng các hàng, tuy nhiên biểu mẫu vẫn bỏ qua thứ tự mới.

Điều cuối cùng mà (loại) hoạt động là thế này:

Trong thực Recipe, xác định sortIngredients() phương pháp mà phân loại ArrayCollection trong bộ nhớ,

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; 
    } 

Sau đó, trong bộ điều khiển:

$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 

Điều này có tác dụng, nhưng biểu mẫu được tạo và xử lý hai lần, và trung thực nó trông giống như một hack ...

Tôi đang tìm cách tốt hơn để giải quyết vấn đề.

Trả lời

9

Bạn cần sử dụng phương thức finishView của loại biểu mẫu của mình.

Dưới đây là ví dụ về mã:

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

công trình !!! Đã dành một nửa ngày này ... cảm ơn bạn. Quá xấu không có nhiều tài liệu trên trang web của Symfony về phương pháp này. – Karolis

Các vấn đề liên quan