Array ke CollectionType dalam bentuk Symfony 3.4

Saya memiliki array Keranjang entitas, dan saya ingin membuat bentuk umum, yang terlihat seperti di layar.

masukkan deskripsi gambar di sini

Seperti yang Anda lihat, saya ingin memiliki bidang Quantity yang dapat diedit di setiap baris, yang mewakili entitas Cart, dan saya ingin memiliki kemampuan untuk memperbarui semuanya sekaligus.

class Cart
{
/**
 * @ORM\Id
 * @ORM\Column(type="integer")
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @ORM\ManyToOne(targetEntity="User", inversedBy="carts")
 */
private $userId;

/**
 * @ORM\ManyToOne(targetEntity="Product", inversedBy="carts")
 */
protected $product;

/**
 * @ORM\Column(type="integer")
 */
private $quantity;

/*gettes & setters */
}

Untuk saat ini, saya memiliki formulir, yang ingin menerima CollectionType, untuk dikerjakan, tetapi - Saya hanya memiliki array entitas, jadi itu membuang LogicalException.

Apa yang perlu saya lakukan - ada cara untuk mengurai array ke CollectionType, atau mungkin saya bisa mengambil sekelompok entitas keranjang dari database dengan cara lain selain itu?:

$carts=$this->getDoctrine()->getRepository(Cart::class)->findByUserId($user);

person D_Jedrzejewski    schedule 25.04.2018    source sumber


Jawaban (1)


Ada contoh bagaimana melakukan apa yang ingin Anda capai di Dokumentasi Symfony di Cara Menyematkan Kumpulan Formulir.

Untuk kasus penggunaan spesifik Anda, Anda ingin membuat UserCartsForm dan CartsForm Terpisah.

Di UserCart Anda, tambahkan bidang carts sebagai CollectionType. Symfony kemudian akan memproses bidang tersebut sebagai rangkaian formulir.

src/AppBundle/Form/UserCart.php

namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type as FormType;

class UserCartsForm extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
         $builder->add('carts', FormType\CollectionType::class, [
             'label' => false,
             'entry_type' => CartsForm::class,
             'entry_options' => array('label' => false),
         ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => User::class,
        ]);
    }
}

Tambahkan bidang yang ingin Anda edit pada formulir Anda ke CartsForm

src/AppBundle/Form/CartsForm.php

namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type as FormType;

class CartsForm extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
         $builder->add('quantity', FormType\IntegerType::class, [
           'label' => false
            //...
         ]);
         //...
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Cart::class,
        ]);
    }
}

Di pengontrol Anda, referensikan entitas pengguna sebagai data UserCartsForm Anda.

src/AppBundle/Controller/DefaultController.php

namespace AppBundle\Controller;

use AppBundle\Form\UserCartsForm;

class DefaultController extends Controller
{

   /**
    * @Route('/user/{id}/carts')
    */
   public function userCartsAction(Request $request, User $user)
   {
      $form = $this->createForm(UserCartsForm::class, $user);
      $form->handleRequest($request);
      if ($form->isSubmitted() && $form->isValid()) {
         //... process entity
         //$this->getDoctrine()->getManager()->flush();
         return $this->redirectToRoute('some_route');
      }

      return $this->render('user_carts_form.html.twig', [
          'form' => $form
      ]);
   }
}

Maka Anda seharusnya dapat dengan mudah mengambil data dari templat ranting Anda untuk dirender sesuai keinginan Anda.

aplikasi/Resources/views/user_carts_form.html.twig

{% form_start(form) %}
   <table>
   <thead>
   <tr>
       <td>Name</td>
       <td>Quantity</td>
       <td></td>
   </tr>
   </thead>
   <tbody>
   {% for cart in form.carts %}
   {% set cartEntity = cart.vars.data %}
   <tr>
       <td>{{ cartEntity.product.name }}</td>
       <td>{{ form_widget(cart.quantity) }}</td>
       <td><a class="button" href="{{ path('remove_cart_action', { id: cartEntity.id }) }}">Delete <icon/></a></td>
   <tr>
   {% endfor %}
   </tbody>
   </table>
   <button type="submit">Submit</button>
{% form_end(form) %}

Pembaruan untuk Batasan Entitas

Secara default Symfony akan menggunakan semua batasan (Default) yang ditetapkan ke entitas saat memvalidasi formulir Anda yang menyebabkan $form->isValid() menghasilkan false.

https://symfony.com/doc/3.4/validation/groups.html

Jika tidak ada grup yang ditentukan, semua batasan milik grup Default akan diterapkan.

Untuk mengatasi masalah ini, gunakan Grup Validasi untuk memisahkan batasan entitas dan mendeklarasikan kelompok yang diinginkan pada formulir masing-masing.

Contoh:

src/AppBundle/Entity/User.php

namespace AppBundle\Entity;

use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 */
class User
{
    
    /**
     * @Assert\NotBlank(groups={"registration"})
     */
    private $username;
    
    //...
}

Kemudian untuk menggunakan grup validasi Anda pada formulir yang diinginkan, dalam hal ini kasus RegistrationForm, Anda mendeklarasikan grup yang diinginkan di AbstractTye::configureOptions sebagai salah satu dari OptionsResolver:$defaults.

src/AppBundle/Form/RegistrationForm.php

namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;

class RegistrationForm extends AbstractType
{
    //...

     public function configureOptions(OptionsResolver $resolver)
     {
         $resolver->setDefaults([
             'data_class' => User::class,
             'validation_groups' => ['registration']
         ]);
     }

}

Sekarang batasan User::NotBlank hanya akan berlaku untuk RegistrationForm::isValid() atau formulir lain yang mendeklarasikan grup validasi pendaftaran.

person Will B.    schedule 25.04.2018
comment
perlu mengubah beberapa hal agar sesuai dengan proyek saya 100%, tapi setidaknya itu berfungsi dengan baik. Terima kasih kawan, aku berhutang banyak padamu bir :D - person D_Jedrzejewski; 26.04.2018
comment
Tapi satu hal lagi - bagaimana cara mengirimkan & menyimpannya dengan benar? Formulir tidak masuk ke pernyataan isValid && isSubowned, jadi hanya mengubah entitas keranjang secara lokal, tanpa menyimpannya ke database - person D_Jedrzejewski; 26.04.2018
comment
Periksa kesalahan formulir untuk melihat mengapa formulir tersebut tidak valid. Saya tidak yakin batasan apa yang Anda miliki pada formulir atau entitas. Anda perlu membuat grup jika batasannya ada pada entitas. Pastikan juga Anda memiliki token CSRF di formulir Anda jika diaktifkan karena hal itu akan mencegah formulir menjadi valid. - person Will B.; 26.04.2018
comment
Itu melempar dan kesalahan dengan bidang kata sandi biasa dari entitas Pengguna, yang memiliki pernyataan NotBlank. Apakah ada cara untuk mematuhinya dengan benar? - person D_Jedrzejewski; 26.04.2018
comment
Dan setelah menghapus pernyataan ini, semuanya berfungsi dengan baik, tetapi jika Anda dapat membantu saya mengatasi kesalahan itu, itu akan sangat bagus... Mungkin seperti saat mengirimkan formulir? Aku tidak tahu... - person D_Jedrzejewski; 26.04.2018
comment
@D_Jedrzejewski memperbarui jawaban dengan contoh grup validasi. - person Will B.; 26.04.2018