2016-09-14 3 views
0

Ich habe ein Formular Hotel, die einige CollectionType enthalten, die wiederum einige CollectionType enthalten. In dieser Form möchte ich eine übergeordnete Entität hinzuzufügen, die mehrere Kinder enthalten kann, die wiederum mehrere Einheiten enthalten:Verschachtelte CollectionTypes

class HotelType extends AbstractType{ 
/** 
* @param FormBuilderInterface $builder 
* @param array $options 
*/ 
public function buildForm(FormBuilderInterface $builder, array $options) 
{ 
    $builder 
     ->add('rooms', CollectionType::class, array(
      'entry_type' => RoomType::class, 
      "label" => "Add rooms", 
      'allow_add' => true, 
      'allow_delete' => true, 
      'prototype' => true, 
     )) 

class RoomType extends AbstractType{ 
/** 
* @param FormBuilderInterface $builder 
* @param array $options 
*/ 
public function buildForm(FormBuilderInterface $builder, array $options){ 
    $builder 

     ->add('pictures', CollectionType::class, array(
      'entry_type' => PictureRoomType::class, 
      "label" => "Add pictures", 
      'allow_add' => true, 
      'allow_delete' => true, 
      'prototype' => true, 
     )) 
     ->add('prices', CollectionType::class, array(
      'entry_type' => PriceRoomType::class, 
      "label" => "Add prices", 
      'allow_add' => true, 
      'allow_delete' => true, 
      'prototype' => true, 
     )) 
    ; 

Hier die Entitäten Beziehung:

class Room { 
/** 
* @ORM\ManyToOne(targetEntity = "Hotel", inversedBy = "rooms") 
* @ORM\JoinColumn(name = "id_hotel", referencedColumnName = "id") 
*/ 
private $hotel; 

/** 
* @ORM\OneToMany(targetEntity="PictureRoom", mappedBy="room", cascade={"remove", "persist"}) 
*/ 
private $pictures; 
/** 
* @ORM\OneToMany(targetEntity="PriceRoom", mappedBy="room", cascade={"remove", "persist"}) 
*/ 
private $prices; 

class Hotel { 
/** 
* @ORM\OneToMany(targetEntity="Room", mappedBy="hotel", cascade={"remove", "persist"}) 
*/ 
private $rooms; 

Die HotelController:

class HotelController extends Controller{ 
/** 
* Creates a new Hotel entity. 
* 
* @Route("/new", name="hotel_new") 
* @Method({"GET", "POST"}) 
*/ 
public function newAction(Request $request) 
{ 
    $hotel = new Hotel(); 
    $form = $this->createForm('AppBundle\Form\HotelType', $hotel); 
    $form->handleRequest($request); 

    if ($form->isSubmitted() && $form->isValid()) { 
     if ($hotel->getRooms() != null) { 
      foreach ($hotel->getRooms() as $room) { 
       if (!empty($room)) { 
        $room->setHotel($hotel); 
        if ($room->getPictures() != null) { 
         foreach ($room->getPictures() as $picture) { 
          if (!empty($picture)) { 
           $picture->setRoom($room); 
           $picture->upload(); 
          } 
         } 
        } 
        if ($room->getPrices() != null) { 
         foreach ($room->getPrices() as $price) { 
          if (!empty($price)) { 
           $price->setRoom($room); 
           $price->setIdTva($price->getIdTva()->getId()); 
          } 
         } 
        } 
        $room->setIdTva($room->getIdTva()->getTva()); 
       } 
      } 
     } 

und ich habe eine JS-Datei, die die Felder handhaben anhängen:

$(document).ready(function() { 

var fields = $('div[data-prototype]'); 
var childElementCount = 1; 

fields.each(function (index) { 
    var field = $(this); 
    var elementCount = 1; 

    field.parent().append('<a href="#" class="btn btn-primary" id="add-another-' + index + '"><i class="glyphicon glyphicon-plus"></i> Add an element</a>'); 

    var trigger = $("#add-another-" + index); 
    var childCollections; 

    trigger.click(function (e) { 
     var newWidget = field.attr('data-prototype'); 
     newWidget = newWidget.replace(/label__/g, ""); 
     newWidget = newWidget.replace(/col-md-6/g, "col-md-12"); 
     newWidget = newWidget.replace(/__name__/g, elementCount); 
     e.preventDefault(); 
     elementCount++; 
     field.parent().append(newWidget); 

     childCollections = field.parent().find('.collection'); 

     if(childCollections.length == 1){ 

      childCollections.parent().append('<a href="#" class="btn btn-primary" id="add-another-' + index + '-'+ elementCount + '"><i class="glyphicon glyphicon-plus"></i> Add an element</a>'); 
      var childTrigger = $('#add-another-' + index + '-' + elementCount); 

      childTrigger.click(function (e) { 
       var newChildWidget = childCollections.find('div[data-prototype]').attr('data-prototype'); 
       //newChildWidget = newChildWidget.replace(/__child__/g, "_" + childElementCount); 
       console.log(newChildWidget); 
       e.preventDefault(); 
       childElementCount += 1; 
       console.log(childElementCount); 
       childCollections.parent().append(newChildWidget); 
      }); 

     } else if (childCollections.length > 1) { 
      childCollections.each(function(childIndex){ 
       var childField = $(this); 
       childField.parent().append('<a href="#" class="btn btn-primary" id="add-another-' + index + '-'+ elementCount + childIndex + '"><i class="glyphicon glyphicon-plus"></i> Add an element</a>'); 
       var childTrigger = $('#add-another-' + index + '-' + elementCount + childIndex); 


       childTrigger.click(function (e) { 
        var newChildWidget = childField.find('div[data-prototype]').attr('data-prototype'); 
        //newChildWidget = newChildWidget.replace(/__child__/g, "_" + childElementCount); 
        console.log(newChildWidget); 

        e.preventDefault(); 
        childElementCount+= 1; 
        console.log(childElementCount); 
        childField.parent().append(newChildWidget); 
       }); 
      }) 
     } 
    }); 
}); 

Das Ereignis funktioniert, wenn ich auf "ein Element hinzufügen" klicken, wird der richtige FormType im richtigen div angehängt. Aber wenn ich die Daten übergebe, bleiben die Enkel-Felder, wie PictureRoom oder PricesRoom, nicht in der Datenbank gespeichert. Kann jemand mit solchen verschachtelten CollectionType-Formularen arbeiten?

Vielen Dank für Ihre Hilfe.

Antwort

2

Es ist wichtig zu verstehen, dass CollectionType eine Eigenschaft von Symfony Form Component ist, und es hat nicht wirklich viel zu Doktrin zu haben.

Also mit CollectionType haben Sie in Ihrer Form Data ArrayCollection von einigen Objekten, aber wie Sie sie verarbeiten und persistieren - es liegt in Ihrer Verantwortung.

Persönlich bevorzuge ich die empty_data Eigenschaft, um neue Entitäten persistent zu machen, die durch CollectionType erstellt werden.

Etwas ist wie

->add('prices', CollectionType::class, array(
     'entry_type' => PriceRoomType::class, 
     "label" => "Add prices", 
     'allow_add' => true, 
     'allow_delete' => true, 
     'prototype' => true, 
     'empty_data' => function (FormInterface $form) { 
      $price = PriceRoom(); 
      $price->setRoom($form->getParent()->getData()); 
      return $price; 
     }, 
    )) 

Das Gleiche gilt für Room und Picture. Und Sie müssen cascade={"remove", "persist"} auf jeder Ebene haben (Zimmer für Hotel).

Nicht sicher in diesem Fall, wenn $form->getParent()->getData()Room Entität haben, aber irgendwie könnte es irgendwie von $form Objekt zugegriffen werden, spielen Sie einfach ein bisschen mit einem Code.

Verwandte Themen