Forms symfony 2.3表单getData不';无法在子窗体集合中工作
我有一个包含集合的表单。因此,我:Forms symfony 2.3表单getData不';无法在子窗体集合中工作,forms,symfony,collections,builder,Forms,Symfony,Collections,Builder,我有一个包含集合的表单。因此,我: /* my type */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('name') ->add('photos','collection',array( 'type'=> new PhotoType(), 'allow_add'=>true))
/* my type */
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('photos','collection',array(
'type'=> new PhotoType(),
'allow_add'=>true));
}
/*Photo Type*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('photoname')
->add('size')
}
但是我想访问照片中的数据,所以我尝试在照片类型中:
$data = $builder->getData();
但它似乎不起作用,即使我正在编辑表单,所以照片收集有数据。
为什么我不能访问另一个调用的表单中的$builder->getData()??因为我试着不去做和eventListener…要理解这里发生了什么,你必须先理解数据映射。当你打电话的时候
$form->setData(array('photoname' => 'Foobar', 'size' => 500));
表单的数据映射器负责获取给定的数组(或对象)并将嵌套值写入表单的字段,即调用
$form->get('photoname')->setData('Foobar');
$form->get('size')->setData(500);
但在您的示例中,您处理的不是Form
,而是FormBuilder
对象FormBuilder
负责收集表单的配置,并使用此信息生成form
实例。因此,FormBuilder
还允许您存储表单的默认数据。但是,由于它只是一个简单的配置对象,因此目前还不会调用数据映射器。例如:
$builder = $factory->createBuilder()
->add('photoname')
->add('size')
->setData(array('photoname' => 'Foobar', 'size' => 500));
print_r($builder->get('photoname')->getData());
print_r($builder->get('size')->getData());
此示例将输出:
null
null
因为数据映射发生在稍后,当我们将FormBuilder
转换为Form
实例时。我们可以使用此事实为各个字段设置单独的默认值:
$builder->add('size', null, array('data' => 100));
// which is equivalent to
$builder->get('size')
->setData(100)
->setDataLocked(true);
print_r($builder->get('photoname')->getData());
print_r($builder->get('size')->getData());
以及输出:
null
100
需要数据锁定以防止数据映射器覆盖您刚才存储的默认数据。如果您传递“数据”选项,这将自动完成
最后,您将构建表单。现在,FormBuilder
在必要时调用Form::setData()
,然后调用数据映射器:
$form = $builder->getForm();
// internally, the following methods are called:
// 1) because of the default data configured for the "size" field
$form->get('size')->setData(100);
// 2) because of the default data configured for the main form
$form->setData(array('photoname' => 'Foobar', 'size' => 500));
// 2a) as a result of data mapping
$form->get('photoname')->setData('Foobar');
// 2b) as a result of data mapping (but ignored, because the data was locked)
$form->get('size')->setData(500);
正如Bernhard指出的,侦听器是实现这一点的唯一方法,因为数据在子表单中还不可用。我使用eventListener来解决类似的需求。下面是我的代码的简化版本,希望对您有所帮助: 我的
视图
实体有一个父表单,它有许多字段,以及其他表单的集合。其中一个子表单用于关联实体ViewVersion
,它实际上需要为动态实体加载另一个表单集合,该动态实体是与视图关联的内容类型。此内容类型可以由许多不同类型的实体之一来定义,例如文章、配置文件等。因此,我需要找出视图
数据中设置的内容类型,然后找到该捆绑包的动态路径,并包括该表单类型
一旦你知道怎么做,其实很容易
class ViewType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// Basic Fields Here
// ...
// ->add('foo', 'text')
// ...
// Load a sub form type for an associated entity
->add('version', new ViewVersionType())
;
}
}
class ViewVersionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// Basic Fields Here
// ...
// ->add('foo', 'text')
// ...
;
// In order to load the correct associated entity's formType,
// I need to get the form data. But it doesn't exist yet.
// So I need to use an Event Listener
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
// Get the current form
$form = $event->getForm();
// Get the data for this form (in this case it's the sub form's entity)
// not the main form's entity
$viewVersion = $event->getData();
// Since the variables I need are in the parent entity, I have to fetch that
$view = $viewVersion->getView();
// Add the associated sub formType for the Content Type specified by this view
// create a dynamic path to the formType
$contentPath = $view->namespace_bundle.'\\Form\\Type\\'.$view->getContentType()->getBundle().'Type';
// Add this as a sub form type
$form->add('content', new $contentPath, array(
'label' => false
));
});
}
}
就这样。我是Symfony的新手,所以在EventListener中做任何事情的想法对我来说都是陌生的(而且似乎不必要的复杂)。但我希望,一旦我更好地理解了这个框架,它将看起来更加直观。如本例所示,使用事件侦听器并不复杂,只需将代码包装在该闭包中(或将其作为一个单独的函数放在它自己的函数中)
我希望这能帮助别人 在提交或编辑过程中,可以在将FormBuilder转换为表单实例时访问数据。对于集合类型,您可以尝试以下方法:
...
$form = $formBuilder->getForm();
...
if ($this->getRestMethod() == 'POST') {
$form->handleRequest($this->get('request'));
if ($form->isValid()) {
$formData = $form->getData();
foreach ($formData['photos'] as $key => $collectionRow) {
var_dump($collectionRow['photoname']);
var_dump($collectionRow['size']);
}
}
}
在我的例子中,在构建表单时不一定需要数据,但在构建视图时(稍后)。在我的子表单类型类的buildForm函数旁边,我添加了buildView函数:
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
class MyType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// ...
}
public function buildView(FormView $view, FormInterface $form, array $options)
{
$data = $form->getData();
$view->vars['name'] = $data->objproporwhatever;
}
// ...
}
由于buildView稍后调用,因此数据在那里可用。在本例中,我使用它更改集合中每个项的表单行的标签。签出。要添加到Chadwick Meyer(在Symfony 4中,但可能适用于早期版本),需要一个事件侦听器来访问集合中的数据,因为很多时候数据尚未创建和/或尚未关联或嵌入到集合中。然而,在日常使用中,通过事件侦听器获取集合中的数据变得非常重要,这与实际获取数据有一些复杂的关系
在照片表单生成器中,必须包含一个事件侦听器:
/*Photo Type*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('photoname')
->add('size');
$builder->addEventListener(FormEvents::POST_SET_DATA,
function (FormEvent $event) {
$form = $event->getForm();
// this would be your entity
$photo = $event->getData();
//Do something with the photo data.
}
);
}
然而。。。如果您想对它做些什么,您需要确保测试空值,因为在实际动态创建数据之前和之后会多次触发事件。例如,如果要动态修改表单,如添加某种提交按钮:
/*Photo Type*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('photoname')
->add('size')
$builder->addEventListener(FormEvents::POST_SET_DATA,
function (FormEvent $event) use ($formModifier) {
$form = $event->getForm();
// this would be your entity
$photo = $event->getData();
$formModifier($form,$photo);
}
);
$formModifier = function (FormInterface $form, Photo $photo = null) {
if (!empty($photo)){//Critical to do this test to avoid errors and get to events with data
$form->add('submitButton', SubmitType::class, array(
'label' => 'Do Something',
));
}
};
}
最后,请注意,在某些情况下,并非所有数据都与特定实体关联,直到它实际持久化到数据库中。例如,如果实体是新创建的,那么它还没有id,而id通常是在持久化过程中由条令或类似规则自动生成的。因此,为了在持久化之前将提交按钮或类似项与集合中的此实体关联,您可能必须使“name”字段唯一,或者为实体创建一个单独的字段,以保存唯一的类型参数,并在持久化之前以唯一的方式生成它,以便在表单创建期间将提交按钮之类的内容与实体相关联。您尝试使用getData()访问数据的位置和原因
?您只描述了什么不起作用,而不是您试图做什么:),但我猜您想使用事件侦听器:我正在尝试做事件侦听器不使用事件侦听器时所做的事情。我只想使用$builder->getData()来查看对象的一些变量,就像在一级表单(不是子表单)中一样。有办法吗?没有,对不起。这就是事件侦听器的用途(我希望我能解释原因)。如果有人能解释为什么您可以在父formBuilder中访问$builder->getData(),但在关联实体的子formType中,您不能,那就太好了。我认为,如果不是整个表单数据,那么子类型关联实体的变量对象至少应该是可访问的。如何访问此子fo中的数据