我有Zend Framework 2表格:
$form = new Form();
$form->add(
[
'name' => 'input1',
'type' => 'Text',
]
);
$fieldset1 = new Fieldset();
$fieldset1->setName('field1');
$fieldset1->add(
[
'name' => 'input2',
'type' => 'Text',
]
);
和它的控制器:
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
$data = $form->getData();
var_dump($this->params()->fromPost(),$data);
exit;
}
}
问题是,当我转储价值时,我得到了这个:
array (size=3)
'input1' => string 'a' (length=1)
'input2' => string 'b' (length=1)
array (size=3)
'input1' => string 'a' (length=1)
'field1' =>
array (size=1)
'input2' => null
那我做错了什么?因为现在在“field2”键中我得到“nulll”。在这种情况下,我如何能够访问fieldset(s)数据(在过滤器,验证等之后)?
更新:正如我所看到的,当我添加到POST
时 <input name="field1[input2]" value="test" />
我得到预期的结果。但为什么zendform不会像那样生成html,而是(错误地)生成:
<input name="input2" />
我做错了什么?
答案 0 :(得分:1)
这里有一个完整的或多或少的简单示例,其中包含实体,输入过滤器,水合器和验证器,用于与字段集一起使用。
首先设置您要使用的字段集类。
namespace Application\Form;
use Zend\Filter\StripTags;
use Zend\Form\Fieldset;
use Zend\Form\Element\Text;
use Zend\InputFilter\InputFilterProviderInterface;
class MyFieldset extends Fieldset implements InputFilterProviderInterface
{
/**
* @see \Zend\Form\Element::init()
*/
public function init()
{
$this->add([
'name' => 'input2',
'type' => Text::class,
'required' => true,
'attributes' => [
'id' => 'input2',
'required' => true,
],
'options' => [
'label' => 'The label for input2 of this fieldset',
],
]);
}
/**
* @see \Zend\InputFilter\InputFilterProviderInterface::getInputFilterSpecification()
*/
public function getInputFilterSpecification()
{
return [
'input2' => [
'required' => true,
'filters' => [
[
'name' => StripTags::class,
],
],
],
];
}
}
您的fieldset类定义了fieldset中的所有输入元素。我鼓励你使用实体类和工厂。这也是此示例使用init方法的原因。在类的构造函数之后调用init方法。使用工厂时,您可以使用构造函数来定义字段集或表单类所需的内容。例如依赖输入字段等。
接下来,您应该为您的字段集编写一个实体。
namespace Application\Entity;
class MyFieldsetEntity
{
protected $input2;
public function getInput2()
{
return $this->input2;
}
public function setInput2($input2)
{
$this->input2 = $input2;
return $this;
}
}
这个简单的实体类将处理您发送给控制器的数据。实体类的一个好处是,您可以在其中定义默认值。如果由于某种原因后期数据应为空,则实体可以返回默认值。我们把它们放在一个工厂中,用于你的场地设置。
namespace Application\Form\Service;
class MyFieldsetFactory
{
public function __invoke(ContainerInterface $container)
{
$hydrator = new ClassMethods(false);
$entity = new MyFieldsetEntity();
return (new MyFieldset())
->setObject($entity)
->setHydrator($hydrator);
}
}
为什么使用智能工厂?因为您可以使用面向对象环境的所有好处。您可以在工厂中定义所需的所有东西。为此,我们创建了一个带有实体和水化器的fieldset实例。这将使用经过筛选和验证的数据来水化字段集。
我们现在需要的只是表单的表单和实体。
namespace ApplicationForm;
use Zend\Form\Element\Text;
use Zend\Form\Form;
class MyForm extends Form
{
public function __construct($name = null, array $options = [])
{
parent::__construct($name, $options);
$this->setAttribute('method', 'post');
$this->add([
'name' => 'input1',
'type' => Text::class,
'required' => true,
'attributes' => [
'id' => 'input2',
'required' => true,
],
'options' => [
'label' => 'The label for input2 of this fieldset',
],
]);
// here goes your fieldset (provided, that your fieldset class is defined in the form elements config in your module.config.php file)
$this->add([
'name' => 'fieldset1',
'type' => MyFieldset::class,
]);
}
}
这就是你的表格。此表单正在实现您的字段集。就这样。现在我们需要一个验证器和这个表单的实体。
namespace Application\Entity;
class MyFormEntity
{
protected $input1;
// we will hydrate this property with the MyFieldsetEntity
protected $fieldset1;
public function getInput1()
{
return $this->input1;
}
public function setInput1($input1)
{
$this->input1 = $input1;
return $this;
}
public function getFieldset1()
{
return $fieldset1;
}
public function setFieldset1($fieldset1)
{
$this->fieldset1 = $fieldset1;
return $this;
}
}
...最后是表单的输入过滤器类。输入过滤器可过滤和验证表单数据。出于安全原因,您应该始终使用输入过滤器等等。
namespace Application\InputFilter;
use Zend\InputFilter\InputFilter;
use Zend\Filter\StripTags;
use Zend\Filter\StringTrim;
class MyFormInputFilter extends InputFilter
{
public function __construct()
{
$this->add([
'name' => 'input1',
'required' => true,
'filters' => [
[
'name' => StripTags::class,
],
[
'name' => StringTrim::class,
],
],
]);
}
}
简单,嗯?此输入过滤器类仅为输入1表单元素设置一些输入过滤器。 fieldset元素由其自身过滤,因为它实现了InputFilterProviderInterface接口。您无需在表单的输入过滤器类中定义更多内容。
将它放在工厂......
namespace Application\Form\Service;
class MyFormFactory
{
public function __invoke(ContainerInterface $container)
{
$entity = new MyFormEntity();
$inputFilter = new MyFormInputFilter();
$hydrator = (new ClassMethods(false))
->addStrategy('fieldset1', new Fieldset1Strategy());
$form = (new MyForm())
->setHydrator($hydrator)
->setObject($entity)
->setInputFilter($inputFilter);
return $form;
}
}
这是您表单的工厂。这家工厂包含一个特殊功能。它为您的保湿剂实例添加了保湿剂策略。如果你的帖子数组中有'fieldset1'键,这个策略会使用fieldset数据来保存你的实体。
这将是保湿策略类...
namespace Application\Hydrator\Strategy;
use Zend\Hydrator\Strategy\DefaultStrategy;
use Zend\Hydrator\ClassMethods;
use Application\Entity\MyFieldsetEntity;
class Fieldset1Strategy extends DefaultStrategy
{
public function hydrate($value)
{
if (!$value instanceof MyFieldsetEntity) {
return (new ClassMethods(false))->hydrate($value, new MyFieldsetEntity());
}
return $value;
}
}
此策略会将MyFieldsetEntity添加到表单实体。 最后一步是在配置文件module.config.php
中定义所有内容// for the forms config provides the form elements key
'form_elements' => [
'factories' => [
YourForm::class => YourFormFactory::class,
YourFormFieldset::class => YourFormFactory::class,
]
],
// can be accessed with $container->get('FormElementsManager')->get(YourFormFieldset::class);
使用示例
这是如何在控制器中使用它的一个小例子。
class ExampleController extends AbstractActionController
{
protected $form;
public function __construct(Form $form)
{
$this->form = $form;
}
public function indexAction()
{
if ($this->getRequest()->isPost()) {
$this->form->setData($this->getRequest()->getPost());
if ($this->form->isValid()) {
$data = $this->form->getData();
\Zend\Debug\Debug::dump($data);
die();
// output will be
// MyFormEntity object
// string input1
// MyFieldsetEntity fieldset1
// string input2
// for fetching the filtered data
// $data->getInput1();
// $data->getFieldset1()->getInput2();
}
}
return [
'form' => $this->form,
];
}
}
在您的视图/模板中,您可以使用zf2提供的不同表单视图帮助程序显示表单。
$form = $this->form;
$form->setAttribute('action', $this->url('application/example'));
$form->prepare();
echo $this->form()->openTag($form);
// outputs the single text input element
echo $this->formRow($form->get('input1'));
// outputs the complete fieldset
echo $this->formCollection($form->get('fieldset1'));
当然,这个答案有点复杂。但我鼓励你试一试。一旦在您的应用程序中实现,这种表单管理是您可以使用的最简单方法。请记住,只是处理原始的帖子数据可能是不安全的。如果你希望过滤后的数据具有对象的好处,建议使用实体,输入过滤器以及zend框架附带的所有其他很酷的东西。
答案 1 :(得分:0)
您尚未将字段集添加到表单中。
$form->add($fieldset1);
答案 2 :(得分:0)
您忘记准备表格了。在$form->prepare()
中,元素的名称已更改为包含字段集的前缀。
如果您使用“表单”视图帮助器,它将为您准备表单。如果不这样做,则必须自己输出“准备”它,例如在视图中,即在输出open标签之前
$this->form->prepare();