gpt4 book ai didi

zend-framework - Zend_Framework 装饰器将 Label 和 ViewHelper 包装在一个 div 中

转载 作者:行者123 更新时间:2023-12-04 02:54:04 25 4
gpt4 key购买 nike

我是新来的,zend 装饰问题,但我有两个重要的问题,我无法理解。问题一后面是一些例子

$decorate = array(
array('ViewHelper'),
array('Description'),
array('Errors', array('class'=>'error')),
array('Label', array('tag'=>'div', 'separator'=>' ')),
array('HtmlTag', array('tag' => 'li', 'class'=>'element')),
);

...

$name = new Zend_Form_Element_Text('title');
$name->setLabel('Title')
->setDescription("No --- way");

$name->setDecorator($decorate);

哪个输出
<li class="element">
<label for="title" class="required">Title</label>
<input type="text" name="title" id="title" value="">
<p class="hint">No --- way</p>
<ul class="error">
<li>Value is required and can't be empty</li>
</ul>
</li>

问题 #1

我如何包装 labelinput围绕一个 div 标签?所以输出如下:
<li class="element">
<div>
<label for="title" class="required">Title</label>
<input type="text" name="title" id="title" value="">
</div>
<p class="hint">No --- way</p>
<ul class="error">
<li>Value is required and can't be empty</li>
</ul>
</li>

问题 #2
elements 的顺序是怎么回事在 $decorate大批?他们毫无意义!

最佳答案

decorator pattern是一种在不改变现有类的情况下向现有类添加功能的设计模式。相反,装饰器类将自己包裹在另一个类周围,并且通常公开与被装饰类相同的接口(interface)。

基本示例:

interface Renderable
{
public function render();
}

class HelloWorld
implements Renderable
{
public function render()
{
return 'Hello world!';
}
}

class BoldDecorator
implements Renderable
{
protected $_decoratee;

public function __construct( Renderable $decoratee )
{
$this->_decoratee = $decoratee;
}

public function render()
{
return '<b>' . $this->_decoratee->render() . '</b>';
}
}

// wrapping (decorating) HelloWorld in a BoldDecorator
$decorator = new BoldDecorator( new HelloWorld() );
echo $decorator->render();

// will output
<b>Hello world!</b>

现在,您可能会想,因为 Zend_Form_Decorator_*类是装饰器,具有 render方法,这自动表示修饰类的输出' render装饰器将始终用附加内容包装方法。但是通过检查我们上面的基本示例,我们可以很容易地看到这并不一定是这样,正如这个附加的(尽管相当无用)示例所示:
class DivDecorator
implements Renderable
{
const PREPEND = 'prepend';
const APPEND = 'append';
const WRAP = 'wrap';

protected $_placement;

protected $_decoratee;

public function __construct( Renderable $decoratee, $placement = self::WRAP )
{
$this->_decoratee = $decoratee;
$this->_placement = $placement;
}

public function render()
{
$content = $this->_decoratee->render();
switch( $this->_placement )
{
case self::PREPEND:
$content = '<div></div>' . $content;
break;
case self::APPEND:
$content = $content . '<div></div>';
break;
case self::WRAP:
default:
$content = '<div>' . $content . '</div>';
}

return $content;
}
}

// wrapping (decorating) HelloWorld in a BoldDecorator and a DivDecorator (with DivDecorator::APPEND)
$decorator = new DivDecorator( new BoldDecorator( new HelloWorld() ), DivDecorator::APPEND );
echo $decorator->render();

// will output
<b>Hello world!</b><div></div>

这其实基本上是多少 Zend_Form_Decorator_*装饰器工作,如果他们有这个放置功能是有意义的。

对于有意义的装饰器,您可以使用 setOption( 'placement', 'append' ) 控制放置。例如,或通过选项 'placement' => 'append'例如,选项数组。

对于 Zend_Form_Decorator_PrepareElements ,例如,这个放置选项是无用的,因此被忽略,因为它准备表单元素以供 ViewScript 使用。装饰器,使其成为不接触被装饰元素的渲染内容的装饰器之一。

根据各个装饰器的默认功能,被装饰类的内容被包装、附加、前置、丢弃 在将内容传递给下一个装饰器之前,对装饰类做了一些完全不同的事情,而不是直接向内容添加一些东西。考虑这个简单的例子:
class ErrorClassDecorator
implements Renderable
{
protected $_decoratee;

public function __construct( Renderable $decoratee )
{
$this->_decoratee = $decoratee;
}

public function render()
{
// imagine the following two fictional methods
if( $this->_decoratee->hasErrors() )
{
$this->_decoratee->setAttribute( 'class', 'errors' );
}

// we didn't touch the rendered content, we just set the css class to 'errors' above
return $this->_decoratee->render();
}
}

// wrapping (decorating) HelloWorld in a BoldDecorator and an ErrorClassDecorator
$decorator = new ErrorClassDecorator( new BoldDecorator( new HelloWorld() ) );
echo $decorator->render();

// might output something like
<b class="errors">Hello world!</b>

现在,当您为 Zend_Form_Element_* 设置装饰器时元素,它们将被包装,并因此按照它们添加的顺序执行。所以,以你的例子为例:
$decorate = array(
array('ViewHelper'),
array('Description'),
array('Errors', array('class'=>'error')),
array('Label', array('tag'=>'div', 'separator'=>' ')),
array('HtmlTag', array('tag' => 'li', 'class'=>'element')),
);

...基本上会发生以下情况(为简洁起见,实际类名被截断):
$decorator = new HtmlTag( new Label( new Errors( new Description( new ViewHelper() ) ) ) );
echo $decorator->render();

因此,在检查您的示例输出时,我们应该能够提炼出各个装饰器的默认放置行为:
// ViewHelper->render()
<input type="text" name="title" id="title" value="">

// Description->render()
<input type="text" name="title" id="title" value="">
<p class="hint">No --- way</p> // placement: append

// Errors->render()
<input type="text" name="title" id="title" value="">
<p class="hint">No --- way</p>
<ul class="error"> // placement: append
<li>Value is required and cant be empty</li>
</ul>

// Label->render()
<label for="title" class="required">Title</label> // placement: prepend
<input type="text" name="title" id="title" value="">
<p class="hint">No --- way</p>
<ul class="error">
<li>Value is required and cant be empty</li>
</ul>

// HtmlTag->render()
<li class="element"> // placement: wrap
<label for="title" class="required">Title</label>
<input type="text" name="title" id="title" value="">
<p class="hint">No --- way</p>
<ul class="error">
<li>Value is required and cant be empty</li>
</ul>
</li>

你知道什么?这实际上是所有各自装饰器的默认位置。

但是现在困难的部分来了,我们需要做什么才能得到你想要的结果?为了包装 labelinput我们不能简单地这样做:
$decorate = array(
array('ViewHelper'),
array('Description'),
array('Errors', array('class'=>'error')),
array('Label', array('tag'=>'div', 'separator'=>' ')),
array('HtmlTag', array('tag' => 'div')), // default placement: wrap
array('HtmlTag', array('tag' => 'li', 'class'=>'element')),
);

...因为这将用 div 包装所有前面的内容( ViewHelperDescriptionErrorsLabel ),对吧?甚至没有......添加的装饰器将被下一个装饰器替换,因为如果装饰器属于同一类,则装饰器将被后续装饰器替换。相反,您必须给它一个唯一的键:
$decorate = array(
array('ViewHelper'),
array('Description'),
array('Errors', array('class'=>'error')),
array('Label', array('tag'=>'div', 'separator'=>' ')),
array(array('divWrapper' => 'HtmlTag'), array('tag' => 'div')), // we'll call it divWrapper
array('HtmlTag', array('tag' => 'li', 'class'=>'element')),
);

现在,我们仍然面临着 divWrapper 的问题。将包装所有前面的内容( ViewHelperDescriptionErrorsLabel )。所以我们需要在这里发挥创造力。有很多方法可以实现我们想要的。我举一个例子,这可能是最简单的:
$decorate = array(
array('ViewHelper'),
array('Label', array('tag'=>'div', 'separator'=>' ')), // default placement: prepend
array(array('divWrapper' => 'HtmlTag'), array('tag' => 'div')), // default placement: wrap
array('Description'), // default placement: append
array('Errors', array('class'=>'error')), // default placement: append
array('HtmlTag', array('tag' => 'li', 'class'=>'element')), // default placement: wrap
);

关于 Zend_Form的更多解释我推荐阅读 Zend Framework 的首席开发人员 Matthew Weier O'Phinney 的 article about Zend Form Decorators

关于zend-framework - Zend_Framework 装饰器将 Label 和 ViewHelper 包装在一个 div 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7546135/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com