Массив в CollectionType в формах Symfony 3.4 - PullRequest
0 голосов
/ 25 апреля 2018

У меня есть массив Cart объектов, и я хочу создать общую форму, которая выглядит на экране.

enter image description here

Как вы видите, я хочу иметь редактируемое поле Количество в каждой строке, которое представляет сущность Корзина, и я хочу иметь возможность обновлять все из них сразу.

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, илиможет быть, я мог бы взять группу объектов корзины из базы данных другим способом?

1014 *

1 Ответ

0 голосов
/ 25 апреля 2018

Пример того, как сделать то, чего вы хотите достичь, приведен в документации 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('/{id}/user-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($carts);
         return $this->redirectToRoute('some_route');
      }

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

Тогда вы сможете легко извлекать данные из шаблона веток для рендеринга так, как вам хочется.

app / 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) %}

Обновление для ограничений сущностей

По умолчанию Symfony будет использовать все ограничения (Default), назначенные сущности при проверке вашей формы, в результате чего $form->isValid() возвращает false.

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()или любая другая форма, которая объявляет группу проверки регистрации.

...