Zend Framework 2 - 表单元素修饰器

10

我想将Zend表单强制转换为Twitter Bootstrap样式。我目前遍历表单字段,将表单信息写入我的Bootstrap div结构中。

我在Zend Framework 1中看到过使用装饰器来实现这一点。但是由于某种原因,版本2的文档没有涵盖此点...

我想做类似于这样的事情:

protected $_format = '<label for="%s">%s</label>'
             . '<input id="%s" name="%s" type="text" value="%s"/>';

public function render($content)
{
    $element = $this->getElement();
    $name    = htmlentities($element->getFullyQualifiedName());
    $label   = htmlentities($element->getLabel());
    $id      = htmlentities($element->getId());
    $value   = htmlentities($element->getValue());

    $markup  = sprintf($this->_format, $name, $label, $id, $name, $value);
    return $markup;
}

有什么想法吗?


看一下各种 Twitter Bootstrap 模块,其中一些具有自定义视图助手,支持大多数/所有选项。例如:https://bitbucket.org/dlu/dlutwbootstrap - Rufinus
我检查了其中几个,但它们无法安装或每个表单需要大约100万行代码...我喜欢我的解决方案,但将其包装在装饰器中会很好...这就是为什么 :) - Ron
Zend\Form没有装饰器,但你可以自由地编写你所概述的视图助手。随便给它取个名字,然后像这样调用它: echo $this->myviewhelper($form->get('elementname')); - Rufinus
4个回答

17

我现在正在使用partials。 我正在迭代属性,为例如CSRFSubmit构建一些异常情况... 这运行得相当顺畅:

视图

echo $this->partial('partial/form-partial', array(
'form' => $this->form,
'url' =>  $this->url('whatever', array('action' => 'add')))); ?>

部分的

<?php
$form = $this->form;
$form->setAttribute ( 'action', $this->url () );
$form->prepare ();

echo $this->form ()->openTag ( $form );
foreach ( $form as $element ) :
?>
    <div
        class="control-group <?php if($this->formElementErrors($element)) echo "error" ?>">
        <label class="control-label"><?php echo $element->getLabel() ?></label>
        <div class="controls">
                <?php echo $this->formElement ( $element );
                    if ($this->formElementErrors ( $element ))
                ?>
            <span class="help-inline"><?php echo $this->formElementErrors($element) ?></span>
        </div>
    </div>
<?php
endforeach;
echo $this->form ()->closeTag ( $form );
?>

为了清晰起见,这里省略了异常情况...


你好,感谢开拓我的思路。 我是zend的新手,但如果我尝试你的代码,隐藏字段或按钮会添加到你的循环中。如何仅在循环中分离出FormRow,而不包括隐藏字段和按钮? - Muhammad Cahya
我猜你需要使用if条件语句。 - Ron

6
我按照@Rufinus提到的方式进行了操作。参见此教程,了解在ZF2中创建视图助手的方法:http://blog.evan.pro/creating-a-simple-view-helper-in-zend-framework-2 在我的情况下,我只想用列表项来包含表单元素,因此我扩展了原始的ZF2视图助手,让它们渲染表单元素。我只是包装了它们返回的内容:
视图助手FormCollection.php
<?php
// ./src/Application/View/Helper/FormCollection.php
namespace Application\View\Helper;

use Zend\Form\ElementInterface;
use Zend\Form\View\Helper\FormCollection as BaseFormCollection;

class FormCollection extends BaseFormCollection {
    public function render(ElementInterface $element) {
        return '<ul>'.parent::render($element).'</ul>';
    }
}

查看助手 FormElement.php

<?php
// ./src/Application/View/Helper/FormElement.php
namespace Application\View\Helper;

use Zend\Form\ElementInterface;
use Zend\Form\View\Helper\FormElement as BaseFormElement;

class FormElement extends BaseFormElement {

    public function render(ElementInterface $element) {
        if ($element->getOption('required')) {
            $req = 'required';
        }
        $type = $element->getAttribute('type');
        $name = $element->getAttribute('name');
        return sprintf('<li class="%s %s %s">%s</li>', $name, $req, $type,  parent::render($element));
    }
}

虽然我的视图看起来像这样,并且不需要修改即可生效。
<?php 
$form = $this->form;
$form->prepare();
echo $this->form()->openTag($form);
echo $this->formCollection($form);
echo $this->form()->closeTag($form);

非常顺利地完成了。


5
我尝试了Ron的Partial方法,结果看起来不是Bootstrap 3所期望的样子。
<form id="tea" name="tea" method="POST" action="/tea/add">
    ...
    <div class="form-group">
        <label class="control-label">Brand</label>
        <div class="form-control">
            <input type="text" value="" name="brand">
        </div>
    ...

我们知道,为了使用Bootstrap 3预定义的表单样式,我们需要将样式定义到输入元素的class属性中:form-control,而不是其包装元素。
我的部分方法如下。
echo $this->form()->openTag($form);
foreach ($form as $element) :?>
    <div class="form-group">
        <?php 
            if ($element->getOption('required')) { $req = 'required'; }
            $type = $element->getAttribute('type');
            $name = $element->getAttribute('name'); 
            $label = $element->getLabel();
        ?>
        <?php if ($name == 'id') { ?>
            <div class="hidden"><?php echo $this->formElement($element); ?></div>
        <?php } else if ($name == 'submit') { ?>
            <input class='btn' name='submit' type='submit' value='Add'>
        <?php } else if ($label != '') { ?>
            <label class="control-label"><?php echo $label ?></label>
            <input class='form-control' name='<?php echo $name ?>' type='<?php echo $type ?>'>
        <?php } ?> 
    </div>
<?php 
endforeach;
echo $this->form()->closeTag();

好的,我们可以得到结果。

<form id="tea" name="tea" method="POST" action="/tea/add">
    ...
    <div class="form-group">
        <label class="control-label">Brand</label>
        <input class="form-control" type="text" name="brand">
    </div>
...

如何将自定义样式附加到zf2表单中已经提到:要向表单元素添加类属性。

class TeaForm extends Form
{
    public function __construct($name = null)
    {
        // we want to ignore the name passed
        parent::__construct('tea');

        $this->add(array(
            'name' => 'id',
            'type' => 'Hidden',
        ));
        $this->add(array(
            'name' => 'brand',
            'type' => 'Text',
            'options' => array(
                'label' => 'Brand',
            ),
            /** **define class attribute** **/
        'attributes' => array(
            'class' => 'form-control',
        ),
        ));
....

看起来很简单,但问题是输入元素将被包装到标签元素中,这仍然不是 Bootstrap 3 所期望的。

<form id="tea" role="form" name="tea" method="POST" action="/tea/add">
    <input type="hidden" value="" name="id">
    <label>
        <span>Name</span>
        <input class="form-control" type="text" value="" name="name">
    </label>
...

在我看来,Partial方法仍然是一种灵活且轻量的选择。Tea Box是一个ZF2实践项目,你可以从Gibhub找到上述所有代码和描述。


要使元素出现在标签外部,该元素需要设置一个“id”属性。 - Richard Parnaby-King

-6

我觉得这很令人困惑。 - user457015
这是我的观点:如果你能写得更简单,就这么做。类似的提示:使用 AnyClass1、AnyClass2; - user2627106
1
以下的echo语句可以缩进,以便更好地阅读。 - user457015
我查看了您的个人资料,以帮助您理解这里的类比:cout << a; cout << b; 这可以写成 cout << a << b; 而且,endl = PHP_EOL。 - user2627106
P.S.:我已经预料到下一个问题了。为了更好地控制渲染,每个项目都要分别绘制。以下是一个适用于集合的示例:https://github.com/dphn/ScContent/blob/master/view/sc-content/file/edit.phtml#L20 - user2627106
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接