อาร์เรย์เป็น CollectionType ในรูปแบบ Symfony 3.4

ฉันมี Array Cart ของเอนทิตี และฉันต้องการสร้างรูปแบบทั่วไปซึ่งดูเหมือนบนหน้าจอ

ป้อนคำอธิบายรูปภาพที่นี่

อย่างที่คุณเห็น ฉันต้องการให้มีฟิลด์จำนวนที่แก้ไขได้ในแต่ละแถว ซึ่งแสดงถึงเอนทิตีรถเข็น และฉันต้องการให้มีความสามารถในการอัปเดตทั้งหมดพร้อมกัน

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 */
}

สำหรับตอนนี้ ฉันมีแบบฟอร์มที่ต้องการรับ CollectionType เพื่อดำเนินการ แต่ - ฉันมีเพียงอาร์เรย์ของเอนทิตีเท่านั้น ดังนั้นจึงทิ้ง LogicalException

สิ่งที่ฉันต้องทำ - มีวิธีใดในการแยกวิเคราะห์อาร์เรย์เป็น CollectionType หรือบางทีฉันอาจนำกลุ่มเอนทิตีรถเข็นจากฐานข้อมูลด้วยวิธีอื่นนอกเหนือจากนั้น:

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

person D_Jedrzejewski    schedule 25.04.2018    source แหล่งที่มา


คำตอบ (1)


มีตัวอย่างวิธีการทำสิ่งที่คุณต้องการบรรลุผลสำเร็จใน เอกสาร Symfony บน วิธีฝังคอลเลกชั่นแบบฟอร์ม

สำหรับกรณีการใช้งานเฉพาะของคุณ คุณจะต้องสร้าง UserCartsForm และ CartsForm แบบแยก

ใน UserCart ของคุณ ให้เพิ่มฟิลด์ carts เป็น CollectionType จากนั้น Symfony จะประมวลผลฟิลด์เป็นชุดของแบบฟอร์ม

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,
        ]);
    }
}

เพิ่มฟิลด์ที่คุณต้องการแก้ไขในแบบฟอร์มของคุณไปยัง 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,
        ]);
    }
}

ในตัวควบคุมของคุณ ให้อ้างอิงเอนทิตีผู้ใช้เป็นข้อมูล UserCartsForm ของคุณ

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

จากนั้นคุณควรจะสามารถดึงข้อมูลจากเทมเพลตทวิกของคุณได้อย่างง่ายดายเพื่อเรนเดอร์ตามที่คุณต้องการ

แอป/ทรัพยากร/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) %}

การอัปเดตข้อจำกัดของเอนทิตี

ตามค่าเริ่มต้น Symfony จะใช้ข้อจำกัดทั้งหมด (Default) ที่กำหนดให้กับเอนทิตีเมื่อตรวจสอบความถูกต้องของแบบฟอร์มของคุณ ทำให้ $form->isValid() ส่งกลับค่าเท็จ

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

หากไม่มีการระบุกลุ่ม ข้อจำกัดทั้งหมดที่อยู่ในกลุ่ม Default จะถูกนำไปใช้

หากต้องการแก้ไขปัญหา ให้ใช้ กลุ่มการตรวจสอบ เพื่อแยกข้อจำกัดของเอนทิตีและประกาศ กลุ่มที่ต้องการในรูปแบบที่เกี่ยวข้อง

ตัวอย่าง:

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

จากนั้นให้ ใช้กลุ่มการตรวจสอบของคุณบนแบบฟอร์มที่ต้องการ ในสิ่งนี้ กรณี RegistrationForm คุณประกาศกลุ่มที่ต้องการใน AbstractTye::configureOptions เป็นหนึ่งใน 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']
         ]);
     }

}

ขณะนี้ข้อจำกัด User::NotBlank จะมีผลกับ RegistrationForm::isValid() หรือแบบฟอร์มอื่นใดที่ประกาศกลุ่มการตรวจสอบความถูกต้องของการลงทะเบียนเท่านั้น

person Will B.    schedule 25.04.2018
comment
จำเป็นต้องเปลี่ยนแปลงบางสิ่งเพื่อให้ตรงกับโครงการของฉันใน 100% แต่อย่างน้อยมันก็ใช้งานได้ดี ขอบคุณเพื่อน ฉันเป็นหนี้เบียร์ก้อนโตให้คุณ :D - person D_Jedrzejewski; 26.04.2018
comment
แต่อีกอย่างหนึ่ง - จะส่งและคงอยู่อย่างถูกต้องได้อย่างไร แบบฟอร์มไม่ได้รับการเข้าสู่คำสั่ง isValid && isSubMIT ดังนั้นจึงเปลี่ยนเฉพาะเอนทิตีรถเข็นในเครื่องเท่านั้น โดยไม่บันทึกลงในฐานข้อมูล - person D_Jedrzejewski; 26.04.2018
comment
ตรวจสอบข้อผิดพลาดของแบบฟอร์มเพื่อดูว่าเหตุใดจึงไม่ผ่านความถูกต้อง ฉันไม่แน่ใจว่าคุณมีข้อจำกัดอะไรบ้างในแบบฟอร์มหรือเอนทิตี คุณจะต้องสร้างกลุ่มหากมีข้อจำกัดในเอนทิตี นอกจากนี้ ตรวจสอบให้แน่ใจว่าคุณมีโทเค็น CSRF ในแบบฟอร์มของคุณ หากเปิดใช้งานไว้ เนื่องจากจะทำให้แบบฟอร์มไม่ถูกต้อง - person Will B.; 26.04.2018
comment
มันพ่นและมีข้อผิดพลาดกับฟิลด์รหัสผ่านธรรมดาจากเอนทิตีผู้ใช้ซึ่งมีการยืนยัน NotBlank มีวิธีเชื่อฟังอย่างถูกต้องหรือไม่? - person D_Jedrzejewski; 26.04.2018
comment
และหลังจากลบการยืนยันนี้ ทุกอย่างก็ใช้ได้ดี แต่ถ้าคุณสามารถช่วยฉันจัดการกับข้อผิดพลาดนั้นได้ก็คงจะดี... บางทีในขณะส่งแบบฟอร์ม ฉันไม่รู้... - person D_Jedrzejewski; 26.04.2018
comment
@D_Jedrzejewski อัปเดตคำตอบพร้อมตัวอย่างกลุ่มการตรวจสอบ - person Will B.; 26.04.2018