Zend framework2 zend framework 2/3集合集自定义属性
从这些问题来判断: 我想没有一个好方法来定制集合的元素。 例如,拥有以下集合:Zend framework2 zend framework 2/3集合集自定义属性,zend-framework2,customization,zend-framework3,zend-form-fieldset,zend-form-collection,Zend Framework2,Customization,Zend Framework3,Zend Form Fieldset,Zend Form Collection,从这些问题来判断: 我想没有一个好方法来定制集合的元素。 例如,拥有以下集合: //path: MyModule\Form\MyFieldset public function __construct($name = null) { parent::__construct('myFieldset'); $this->add([ 'name'=>'test', 'type' => Element\Collection::c
//path: MyModule\Form\MyFieldset
public function __construct($name = null) {
parent::__construct('myFieldset');
$this->add([
'name'=>'test',
'type' => Element\Collection::class,
'options' => [
'label' => 'MyCollection',
'count' => 6,
'should_create_template' => true,
'target_element' => new Element\Text()
],
]);
}
然后执行一些操作,以便为每个文本元素和/或自动编号的标签定义(此处,在当前类中)自定义属性,然后输出(只需调用zend helper FormCollection,而无需任何自定义视图帮助器):
文本元素n°1
文本元素编号2
[...]
我错了吗?
(我问这个问题是因为我找到了一个很好的解决方案,也许发布它会有所帮助)
target\u元素必须引用一个字段集。这可以是集合所在表单中的新实例,也可以是类名
例如:
$fieldset = new Fieldset();
$fieldset->add([
'name' => 'some_field_name',
'type' => 'text',
]);
$this->add([
'name'=>'test',
'type' => Element\Collection::class,
'options' => [
'label' => 'MyCollection',
'count' => 6,
'should_create_template' => true,
'target_element' => $fieldset
],
]);
namespace Module\Form;
use Zend\Form\Fieldset;
class MyFieldset extends Fieldset {
public static $instance_count = 1;
public function __construct() {
parent::__construct();
$this->add([
'name' => 'question',
'type' => 'text',
'attributes' => [
'alt' => 'input' . MyFieldset::$instance_count,
],
'options' => [
'label' => 'Text element No ' . MyFieldset::$instance_count,
],
]);
MyFieldset::$instance_count++;
}
}
或
在为每个输入定制标签方面,我还没有找到一种方法
不太确定集合的内部工作方式,但我怀疑它会根据需要创建尽可能多的target\u元素的新实例。就向标签(或任意属性)添加数字而言,您可以使用以1
开头的静态属性创建一个fieldset类,将其添加到标签并增加其值
例如:
$fieldset = new Fieldset();
$fieldset->add([
'name' => 'some_field_name',
'type' => 'text',
]);
$this->add([
'name'=>'test',
'type' => Element\Collection::class,
'options' => [
'label' => 'MyCollection',
'count' => 6,
'should_create_template' => true,
'target_element' => $fieldset
],
]);
namespace Module\Form;
use Zend\Form\Fieldset;
class MyFieldset extends Fieldset {
public static $instance_count = 1;
public function __construct() {
parent::__construct();
$this->add([
'name' => 'question',
'type' => 'text',
'attributes' => [
'alt' => 'input' . MyFieldset::$instance_count,
],
'options' => [
'label' => 'Text element No ' . MyFieldset::$instance_count,
],
]);
MyFieldset::$instance_count++;
}
}
我找到的解决方案与Richard Parnaby King提供的解决方案有一些共同之处:
目标元素必须引用字段集
但是,与设置克隆计数器相反,它扩展了Zend\Form\Fieldset方法prepareElement
基本应用:
namespace Module\Form;
use Zend\Form\Fieldset;
use Zend\Form\FormInterface; //needed in order to call prepareElement method
class MyFieldset extends Fieldset {
public function __construct($name = null) {
parent::__construct($name);
$this->add([
'name' => 'question',
'type' => 'text',
'attributes' => [
'alt' => 'input',
],
'options' => [
'label' => 'Text',
],
]);
}//construct
public function prepareElement(FormInterface $form){
parent::prepareElement($form);
$name = $this->getName();
//Do stuff related to this fieldset
foreach ($this->iterator as $elementOrFieldset) {
$elementName=$elementOrFieldset->getName()
//Do stuff related to this fieldset children
}
}//prepareElement
}
特点:
自动编号标签和/或属性
允许有条件地分配属性/标签
允许不同元素之间的交互(例如:将元素A id作为目标传递给元素B)
使用模板
由于这个解决方案可以通过多种方式开发,我准备了一个完整的演示,可以运行和探索
注意:此演示不是最佳的实现,而是一组示例,可以得出一个结果。:-)
本示例旨在使用前缀“Bob”在默认模块“Application”下运行,以避免与其他文件发生冲突(我想象有人可能已经有一个名为TestController的文件,但我猜没有人有一个名为BobController的文件)
然后,如果您完全按照下面的步骤操作,您应该能够毫无问题地运行和探索演示
prepareElement
方法在BobFieldset
类中的实现可能看起来很庞大,但这只是注释、空格和示例的问题。根据您的需要,它可能非常小
第1步:
namespace Module\Form;
use Zend\Form\Fieldset;
use Zend\Form\FormInterface; //needed in order to call prepareElement method
class MyFieldset extends Fieldset {
public function __construct($name = null) {
parent::__construct($name);
$this->add([
'name' => 'question',
'type' => 'text',
'attributes' => [
'alt' => 'input',
],
'options' => [
'label' => 'Text',
],
]);
}//construct
public function prepareElement(FormInterface $form){
parent::prepareElement($form);
$name = $this->getName();
//Do stuff related to this fieldset
foreach ($this->iterator as $elementOrFieldset) {
$elementName=$elementOrFieldset->getName()
//Do stuff related to this fieldset children
}
}//prepareElement
}
编辑文件:Application\config\module.config.php
//add bob route to router
'router' => [
'routes' => [
'bob' => [
'type' => Literal::class,
'options' => [
'route' => '/bob',
'defaults' => [
'controller' => Controller\BobController::class,
'action' => 'index',
],
],
],
[...]
//add BobController
'controllers' => [
'factories' => [
[...]
Controller\BobController::class => InvokableFactory::class,
],
],
第二步:
namespace Module\Form;
use Zend\Form\Fieldset;
use Zend\Form\FormInterface; //needed in order to call prepareElement method
class MyFieldset extends Fieldset {
public function __construct($name = null) {
parent::__construct($name);
$this->add([
'name' => 'question',
'type' => 'text',
'attributes' => [
'alt' => 'input',
],
'options' => [
'label' => 'Text',
],
]);
}//construct
public function prepareElement(FormInterface $form){
parent::prepareElement($form);
$name = $this->getName();
//Do stuff related to this fieldset
foreach ($this->iterator as $elementOrFieldset) {
$elementName=$elementOrFieldset->getName()
//Do stuff related to this fieldset children
}
}//prepareElement
}
创建文件:Application\src\Controller\BobController.php
<?php
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Application\Form\BobForm;
class BobController extends AbstractActionController
{
public function __construct(){}
public function indexAction()
{
$form = new BobForm('album');
$request = $this->getRequest();
if( $request->isPost()){
$form->setInputFilter($form->getInputFilter());
$form->setData($request->getPost());
if (! $form->isValid()) {
return ['form' => $form];
}
}
return ['form' => $form];
}
}
我刚刚意识到还有另一个更好、更灵活的解决方案:扩展collection元素(为什么我以前没有尝试过呢?)
这种方法的主要优点是不需要拆分元素的名称:“克隆号”([0]、[1]、…
)可以直接访问
功能:
namespace Module\Form;
use Zend\Form\Fieldset;
use Zend\Form\FormInterface; //needed in order to call prepareElement method
class MyFieldset extends Fieldset {
public function __construct($name = null) {
parent::__construct($name);
$this->add([
'name' => 'question',
'type' => 'text',
'attributes' => [
'alt' => 'input',
],
'options' => [
'label' => 'Text',
],
]);
}//construct
public function prepareElement(FormInterface $form){
parent::prepareElement($form);
$name = $this->getName();
//Do stuff related to this fieldset
foreach ($this->iterator as $elementOrFieldset) {
$elementName=$elementOrFieldset->getName()
//Do stuff related to this fieldset children
}
}//prepareElement
}
自动编号标签和/或属性
允许有条件地分配属性/标签
允许不同元素之间的交互(有限,请参阅下面的问题)
使用模板(使用占位符->),无需检查索引是否为数字(这是我的另一个解决方案的问题)
目标元素可以是一个简单的元素,无需实现Zend/Form/Fieldset
问题:
namespace Module\Form;
use Zend\Form\Fieldset;
use Zend\Form\FormInterface; //needed in order to call prepareElement method
class MyFieldset extends Fieldset {
public function __construct($name = null) {
parent::__construct($name);
$this->add([
'name' => 'question',
'type' => 'text',
'attributes' => [
'alt' => 'input',
],
'options' => [
'label' => 'Text',
],
]);
}//construct
public function prepareElement(FormInterface $form){
parent::prepareElement($form);
$name = $this->getName();
//Do stuff related to this fieldset
foreach ($this->iterator as $elementOrFieldset) {
$elementName=$elementOrFieldset->getName()
//Do stuff related to this fieldset children
}
}//prepareElement
}
设置ID可能有问题,因为(2)
从扩展脚本无法访问最终元素的名称(例如:
fieldset[subfieldset][0][elementName]
),因为稍后将按层次结构构建它
工作原理:
namespace Module\Form;
use Zend\Form\Fieldset;
use Zend\Form\FormInterface; //needed in order to call prepareElement method
class MyFieldset extends Fieldset {
public function __construct($name = null) {
parent::__construct($name);
$this->add([
'name' => 'question',
'type' => 'text',
'attributes' => [
'alt' => 'input',
],
'options' => [
'label' => 'Text',
],
]);
}//construct
public function prepareElement(FormInterface $form){
parent::prepareElement($form);
$name = $this->getName();
//Do stuff related to this fieldset
foreach ($this->iterator as $elementOrFieldset) {
$elementName=$elementOrFieldset->getName()
//Do stuff related to this fieldset children
}
}//prepareElement
}
1。扩展系列
//file: Application\src\Form\Element\ExtendedCollection.php
<?php
namespace Application\Form\Element;
use Zend\Form\Element\Collection;
class ExtendedCollection extends Collection
{
protected $autonumbering_callback = false;
protected $autonumbering_callback_options = [];
public function setOptions($options)
{
parent::setOptions($options);
if (isset($options['autonumbering_callback'])) {
$this->autonumbering_callback=(isset($options['autonumbering_callback'][0])) ? $options['autonumbering_callback'][0] : $options['autonumbering_callback'];
$this->autonumbering_callback_options=(isset($options['autonumbering_callback'][1])) ? $options['autonumbering_callback'][1] : [];
}
return $this;
}
protected function addNewTargetElementInstance($key)
{
//Original instructions
$this->shouldCreateChildrenOnPrepareElement = false;
$elementOrFieldset = $this->createNewTargetElementInstance();
$elementOrFieldset->setName($key);
$this->add($elementOrFieldset);
if (! $this->allowAdd && $this->count() > $this->count) {
throw new Exception\DomainException(sprintf(
'There are more elements than specified in the collection (%s). Either set the allow_add option ' .
'to true, or re-submit the form.',
get_class($this)
));
}
//Callback
if ($this->autonumbering_callback && method_exists(...$this->autonumbering_callback) && is_callable($this->autonumbering_callback)){
call_user_func_array($this->autonumbering_callback,[$elementOrFieldset,$key,$this->autonumbering_callback_options]);
}
return $elementOrFieldset;
}
}
//文件:Application\src\Form\Element\ExtendedCollection.php
我已经提交了另一个(我相信更好的)解决方案。请检查一下,给我你的意见。
//file: Application\src\Form\BobForm.php
<?php
namespace Application\Form;
use Zend\Form\Form;
use Zend\Form\Fieldset; //needed for myCallback3
use Application\Form\Element\ExtendedCollection;
class BobForm extends Form
{
private $inputFilter;
public function __construct($name = null)
{
parent::__construct($name);
$this->add([
'name' => 'answer',
'type' => ExtendedCollection::class,
'options' => [
'count' =>3,
'should_create_template' => true,
'target_element' => new \Application\Form\BobFieldset2 ,
'autonumbering_callback'=>[
[$this,'myCallback'],
['attributes'=>['title','data-something'],'whateverYouWant'=>'something',]
],
],
]);
}
public function myCallback($elementOrFieldset, $key, $params){
foreach($params['attributes'] as $attr){
$autoNumAttr=str_replace('__num__',($key),$elementOrFieldset->getAttribute($attr));
$elementOrFieldset->setAttribute($attr,$autoNumAttr);
}//foreach
$label = str_replace('__num__',($key+1),$elementOrFieldset->getLabel());
$elementOrFieldset->setLabel($label);
}
public function myCallback2($elementOrFieldset, $key, $params){
$char='a';
foreach(range(1,$key) as $i) {
if($key>0){$char++;}
}
$elementOrFieldset->setLabel('Answer '.$char);
}
public function myCallback3($elementOrFieldset, $key, $params, $isChild=null){
if(!$isChild){$elementOrFieldset->setLabel('Answer '.($key+1));}
else{$elementOrFieldset->setLabel($key);}
//don't forget: use Zend\Form\Fieldset;
if($elementOrFieldset instanceof Fieldset && !$isChild){
$char='a';
foreach($elementOrFieldset as $item){
$this->myCallback3($item,($key+1 .$char++.') '),null,1);
}
}
}
}