Ang*_*.47 10 zend-framework zend-form zend-decorators
我是新手,zend装饰malarchy,但我有两个重要问题,我无法理解.问题一之后是一些例子
$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);
Run Code Online (Sandbox Code Playgroud)
哪个输出
<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>
Run Code Online (Sandbox Code Playgroud)
我如何包装label和input围绕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>
Run Code Online (Sandbox Code Playgroud)
用什么的顺序是向上elements的在$decorate阵?他们没有感觉!
Dec*_*ler 21
的装饰图案是用于添加功能的现有的类,而不改变这些现有的类的设计模式.相反,装饰器类将自己包装在另一个类周围,并且通常公开与装饰类相同的接口.
基本示例:
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>
Run Code Online (Sandbox Code Playgroud)
现在,您可能会想到因为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>
Run Code Online (Sandbox Code Playgroud)
事实上,这实际上是很多Zend_Form_Decorator_*装饰器的工作方式,如果它们具有这种放置功能是有意义的.
对于有意义的装饰器,您可以使用setOption( 'placement', 'append' )例如控制放置,或者将选项传递'placement' => 'append'给options数组.
为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>
Run Code Online (Sandbox Code Playgroud)
现在,当您为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')),
);
Run Code Online (Sandbox Code Playgroud)
...基本上会发生以下情况(为简洁而截断的实际类名称):
$decorator = new HtmlTag( new Label( new Errors( new Description( new ViewHelper() ) ) ) );
echo $decorator->render();
Run Code Online (Sandbox Code Playgroud)
因此,在检查您的示例输出时,我们应该能够提取单个装饰器的默认放置行为:
// 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>
Run Code Online (Sandbox Code Playgroud)
你知道什么; 这实际上是所有相应装饰器的默认位置.
但现在是困难的部分,我们需要做些什么来获得您正在寻找的结果?为了包装label而input我们不能简单地这样做:
$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')),
);
Run Code Online (Sandbox Code Playgroud)
......因为这将包装所有前面的内容(ViewHelper,Description,Errors和Label)有一个div,对不对?甚至没有......添加的装饰器将被下一个装饰器替换,因为装饰器被以下装饰器替换,如果它是同一个类.相反,你必须给它一个独特的钥匙:
$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')),
);
Run Code Online (Sandbox Code Playgroud)
现在,我们仍然面临着这个问题divWrapper将包裹前面的所有内容(ViewHelper,Description,Errors和Label).所以我们需要在这里发挥创意.有很多方法可以达到我们想要的效果.我举一个例子,这可能是最简单的:
$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
);
Run Code Online (Sandbox Code Playgroud)
有关Zend_Form装饰器的更多解释,我建议阅读Zend Framework的首席开发人员Matthew Weier O'Phinney 关于Zend Form装饰器的文章
| 归档时间: |
|
| 查看次数: |
7524 次 |
| 最近记录: |