Symfony2:将表单类型指定为另一个表单的字段类型
Symfony2: Specify form type as a field type of another form
所以我有一个基本形式:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('firstName')
->add('lastName')
->add('checklist);
}
其中有一个特定的字段checklist
。我创建了一个模型 class,它描述了清单中的所有可能选项
ChecklistModel.php
class ChecklistModel {
/** @var string **/
protected $clientSatisfied;
// ... getters and setters
}
然后,我专门为Checklist创建了一个表单类型。
ChecklistFormType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('clientSatisfied', ChoiceType::class, array(
'choices' => array(
'yes' => 'yes',
'no' => 'no'
),
'choices_as_values' => true,
))
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => ChecklistModel::class
));
}
我想在数据库中将清单存储为一个简单的 JSON 字符串,但我想使用 ChecklistModel
来确保正确提交清单中的所有字段。
我的问题是如何告诉 Symfony 使用 ChecklistFormType
作为基本表单的字段类型 checklist
属性?
我试过
->add('checklist', ChecklistFormType::class);
但我收到以下错误
The form's view data is expected to be an instance of class PT\MyBundle\Models\Invoice\ChecklistModel, but is a(n) string. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms a(n) string to an instance of PT\MyBundle\Models\Invoice\ChecklistModel
您必须按照错误消息中的指示指定数据 class,并结合 de/serializer 定义数据转换器。
Symfony documentation
基于我上面的评论,我建议不要在表单类型中进行数据转换(尽管这当然是可能的),而是在使用 json_array type
.
的封装模型中进行数据转换
这样只有该模型真正知道数据将如何持久化。
两个相关模型:
src/AppBundle/Entity/FooModel.php
<?php
declare(strict_types=1);
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class FooModel
{
// other properties (firstName, lastName, ...)
/**
* @var array
*
* @ORM\Column(type="json_array")
*/
private $checklist = [];
/**
* @param ChecklistModel $checklist
*/
public function setChecklist(ChecklistModel $checklist)
{
$this->checklist = $checklist->toArray();
}
/**
* @return ChecklistModel
*/
public function getChecklist(): ChecklistModel
{
return ChecklistModel::fromArray($this->checklist);
}
}
ChecklistModel
实施上述方法:
src/AppBundle/Entity/ChecklistModel.php
<?php
declare(strict_types=1);
namespace AppBundle\Entity;
class ChecklistModel
{
// properties and getters/setters
/**
* @param array $data
*
* @return ChecklistModel
*/
public static function fromArray(array $data): ChecklistModel
{
$result = new self;
foreach (get_class_vars(self::class) as $k => $v) {
if (isset($data[$k])) {
$result->$k = $data[$k];
}
}
return $result;
}
/**
* @return array
*/
public function toArray()
{
return get_object_vars($this);
}
}
表格类型:
src/AppBundle/Form/FooFormType.php
<?php
declare(strict_types=1);
namespace AppBundle\Form;
use AppBundle\Entity\FooModel;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type as FormType;
class FooFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('firstName', FormType\TextType::class)
->add('lastName', FormType\TextType::class)
->add('checklist', ChecklistFormType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => FooModel::class,
'empty_data' => new FooModel(),
]);
}
}
src/AppBundle/Form/ChecklistFormType.php
<?php
declare(strict_types=1);
namespace AppBundle\Form;
use AppBundle\Entity\ChecklistModel;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type as FormType;
class ChecklistFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('clientSatisfied', FormType\ChoiceType::class, [
'choices' => [
'yes' => 'yes',
'no' => 'no'
],
'choices_as_values' => true,
])
->add('clientNewCustomer', FormType\ChoiceType::class, [
'choices' => [
'yes' => 'yes',
'no' => 'no'
],
'choices_as_values' => true,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => ChecklistModel::class,
'empty_data' => new ChecklistModel(),
]);
}
}
用法示例
public function indexAction(Http\Request $request)
{
$em = $this->getDoctrine()->getManager();
$data = new Entity\FooModel();
$form = $this
->createForm(FooFormType::class, $data)
->handleRequest($request)
;
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($data);
$em->flush();
}
return $this->render('default/index.html.twig', [
'form' => $form->createView(),
'data' => $form->getData(),
]);
}
这样 ChecklistFormType
就不需要知道数据是 json 或其他什么。一个ChecklistModel
进进出出,不出意外。
也就是说,embeddables 在这里可能是更好的选择。
所以我有一个基本形式:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('firstName')
->add('lastName')
->add('checklist);
}
其中有一个特定的字段checklist
。我创建了一个模型 class,它描述了清单中的所有可能选项
ChecklistModel.php
class ChecklistModel {
/** @var string **/
protected $clientSatisfied;
// ... getters and setters
}
然后,我专门为Checklist创建了一个表单类型。
ChecklistFormType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('clientSatisfied', ChoiceType::class, array(
'choices' => array(
'yes' => 'yes',
'no' => 'no'
),
'choices_as_values' => true,
))
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => ChecklistModel::class
));
}
我想在数据库中将清单存储为一个简单的 JSON 字符串,但我想使用 ChecklistModel
来确保正确提交清单中的所有字段。
我的问题是如何告诉 Symfony 使用 ChecklistFormType
作为基本表单的字段类型 checklist
属性?
我试过
->add('checklist', ChecklistFormType::class);
但我收到以下错误
The form's view data is expected to be an instance of class PT\MyBundle\Models\Invoice\ChecklistModel, but is a(n) string. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms a(n) string to an instance of PT\MyBundle\Models\Invoice\ChecklistModel
您必须按照错误消息中的指示指定数据 class,并结合 de/serializer 定义数据转换器。 Symfony documentation
基于我上面的评论,我建议不要在表单类型中进行数据转换(尽管这当然是可能的),而是在使用 json_array type
.
这样只有该模型真正知道数据将如何持久化。
两个相关模型:
src/AppBundle/Entity/FooModel.php
<?php
declare(strict_types=1);
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
*/
class FooModel
{
// other properties (firstName, lastName, ...)
/**
* @var array
*
* @ORM\Column(type="json_array")
*/
private $checklist = [];
/**
* @param ChecklistModel $checklist
*/
public function setChecklist(ChecklistModel $checklist)
{
$this->checklist = $checklist->toArray();
}
/**
* @return ChecklistModel
*/
public function getChecklist(): ChecklistModel
{
return ChecklistModel::fromArray($this->checklist);
}
}
ChecklistModel
实施上述方法:
src/AppBundle/Entity/ChecklistModel.php
<?php
declare(strict_types=1);
namespace AppBundle\Entity;
class ChecklistModel
{
// properties and getters/setters
/**
* @param array $data
*
* @return ChecklistModel
*/
public static function fromArray(array $data): ChecklistModel
{
$result = new self;
foreach (get_class_vars(self::class) as $k => $v) {
if (isset($data[$k])) {
$result->$k = $data[$k];
}
}
return $result;
}
/**
* @return array
*/
public function toArray()
{
return get_object_vars($this);
}
}
表格类型:
src/AppBundle/Form/FooFormType.php
<?php
declare(strict_types=1);
namespace AppBundle\Form;
use AppBundle\Entity\FooModel;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type as FormType;
class FooFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('firstName', FormType\TextType::class)
->add('lastName', FormType\TextType::class)
->add('checklist', ChecklistFormType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => FooModel::class,
'empty_data' => new FooModel(),
]);
}
}
src/AppBundle/Form/ChecklistFormType.php
<?php
declare(strict_types=1);
namespace AppBundle\Form;
use AppBundle\Entity\ChecklistModel;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type as FormType;
class ChecklistFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('clientSatisfied', FormType\ChoiceType::class, [
'choices' => [
'yes' => 'yes',
'no' => 'no'
],
'choices_as_values' => true,
])
->add('clientNewCustomer', FormType\ChoiceType::class, [
'choices' => [
'yes' => 'yes',
'no' => 'no'
],
'choices_as_values' => true,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => ChecklistModel::class,
'empty_data' => new ChecklistModel(),
]);
}
}
用法示例
public function indexAction(Http\Request $request)
{
$em = $this->getDoctrine()->getManager();
$data = new Entity\FooModel();
$form = $this
->createForm(FooFormType::class, $data)
->handleRequest($request)
;
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($data);
$em->flush();
}
return $this->render('default/index.html.twig', [
'form' => $form->createView(),
'data' => $form->getData(),
]);
}
这样 ChecklistFormType
就不需要知道数据是 json 或其他什么。一个ChecklistModel
进进出出,不出意外。
也就是说,embeddables 在这里可能是更好的选择。