Symfony 3.4 表单中的数组到 CollectionType
Array to CollectionType in Symfony 3.4 forms
我有实体的数组 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);
Symfony Documentation on How to Embed a Collection of Forms.
中有一个示例说明如何实现您想要实现的目标
对于您的特定用例,您需要创建一个 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
]);
}
}
然后您应该能够轻松地从您的 twig 模板中检索数据以按照您的意愿呈现。
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()
到 return 错误。
https://symfony.com/doc/3.4/validation/groups.html
If no groups are specified, all constraints that belong to the group
Default
will be applied.
要解决此问题,请使用 Validation Groups 分隔实体约束并在各自的表单上声明所需的组。
示例:
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;
//...
}
然后到 use your validation group(s) 所需的表格,在本例中为 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()
或声明注册验证组的任何其他形式。
我有实体的数组 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);
Symfony Documentation on How to Embed a Collection of Forms.
中有一个示例说明如何实现您想要实现的目标对于您的特定用例,您需要创建一个 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
]);
}
}
然后您应该能够轻松地从您的 twig 模板中检索数据以按照您的意愿呈现。
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()
到 return 错误。
https://symfony.com/doc/3.4/validation/groups.html
If no groups are specified, all constraints that belong to the group
Default
will be applied.
要解决此问题,请使用 Validation Groups 分隔实体约束并在各自的表单上声明所需的组。
示例:
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;
//...
}
然后到 use your validation group(s) 所需的表格,在本例中为 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()
或声明注册验证组的任何其他形式。