Zend Framework 2 - Form Element Decorators

有些话、适合烂在心里 提交于 2019-11-28 18:57:42
Ron

I'm using partials now. I'm iterating over the attributes, build a few exceptions for eg CSRF and Submit... This works pretty smooth:

View

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

Partial

<?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 );
?>

The exceptions are left out for clearity's sake...

I did it the way @Rufinus mentioned. See this Tutorial on how to create View Helpers in ZF2 http://blog.evan.pro/creating-a-simple-view-helper-in-zend-framework-2

In my case I simply wanted to wrap form elements with list items so I extended the original ZF2 View Helpers and let them do the rendering of the elements. I Just wrapped what they return:

View Helper 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>';
    }
}

View Helper 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));
    }
}

while my view looks like this and didn't need to be modified for the changes to take effect.

<?php 
$form = $this->form;
$form->prepare();
echo $this->form()->openTag($form);
echo $this->formCollection($form);
echo $this->form()->closeTag($form);

worked like a charm.

John Yin

I tried Ron's Partial method, the result would like this which not Bootstrap 3 intended.

<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>
    ...

We know, in order to use bootstrap 3 predefined Form style, we need to define style to input element: form-control, rather than its wrapping element.

My Partial way is as following.

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();

Well, we could get the result.

<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>
...

How to attach custom styles into zf2 forms has mentioned : to add class attribute to the Form element.

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',
        ),
        ));
....

It looks quite simple, but, the problem is the input element would be wrapped into the label element, which still not what Bootstrap 3 intended.

<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>
...

In my opinion, the Partial method is still one flexible and light choice. Tea Box is one ZF2 practice, you could find all above mentioned code and description from Gibhub

This will make the code easier.

http://php.net/manual/en/function.echo.php

<?php 

$form->prepare();
echo 
$this->form()->openTag($form),
$this->formCollection($form),
$this->form()->closeTag($form);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!