Zend Framework 1.10.1 理解和使用 Zend 表单装饰器之五:创建和呈现复合元素
2010-04-08 14:21
519 查看
在上一节中,我们有一个展示一个出生日期元素的例子:
<div class="element">
<?php echo $form->dateOfBirth->renderLabel(0 ?>
<?php echo $this->formText('dateOfBirth[day]', '', array('size' => 2, 'maxlength' =>2)) ?>
/
<?php echo $this->formText('dateOfBirth[month]', '', array('size' => 2, 'maxlength' =>2)) ?>
/
<?php echo $this->formText('dateOfBirth[year]', '', array('size' => 4, 'maxlength' => 4)) ?>
</div>
你如何把这个元素当作一个 Zend_Form_Element 来展现?你如何写一个装饰器来呈现它?
元素
元素是如何工作的,这个问题包括:
你如何设置和检索值?
你如何验证值?
不管其它的,你如何允许分离的表单 input 接受这三个片断(日,月,年)?
头两个问题围绕表单元素它自己:setValue() 和 getValue() 是如何工作的?事实上由这个问题可以暗示到关于装饰器的一个问题:你如何检索从元素得来的分离的数据片断以及/或者设置它们?
解决的办法是重写你的元素的 setValue() 方法来提供一些定制的逻辑。在这个特定的例子,我们的元素应该有三个分离的行为:
如果提供一个整型的时间戳,它应该被用作确定和储存日,月和年。
如果提供一个文字字符串,它应该能被转换成一个时间戳,然后这个值会用作确定和储存日,月和年。
如果提供一个包括日,月和年为键值的数组,那些值将会被储存。
内部的,日,月和年将被分别储存。当元素的值被检索到的时候,它将以一种规范化的字符串格式储存。我们重写 getValue() 也把分离的数据片断组合进一个最终的字符串。
我们的类将看起来是这样的:
class My_Form_Element_Date extends Zend_Form_Element_Xhtml
{
protected $_dateFormat = '%year%-%month%-%day%';
protected $_day;
protected $_month;
protected $_year;
public function setDay($value)
{
$this->_day = (int) $value;
return $this;
}
public function getDay()
{
return $this->_day;
}
public function setMonth($value)
{
$this->_month = (int) $value;
return $this;
}
public function getMonth()
{
return $this->_month;
}
public function setYear($value)
{
$this->_year = (int) $value;
return $this;
}
public function getYear()
{
return $this->_year;
}
public function setValue($value)
{
if (is_int($value)) {
$this->setDay(date('d', $value))
->setMonth(date('m', $value))
->setYear(date('Y', $value));
} elseif (is_string($value)) {
$date = strtotime($value);
$this->setDay(date('d', $date))
->setMonth(date('m', $date))
->setYear(date('Y', $date));
} elseif (is_array($value)
&& (isset($value['day'])
&& isset($value['month'])
&& isset($value['year'])
)
) {
$this->setDay($value['day'])
->setMonth($value['month'])
->setYear($value['year']);
} else {
throw new Exception('Invalid date value provided');
}
return $this;
}
public function getValue()
{
return str_replace(
array('%year%', '%month%', '%day%'),
array($this->getYear(), $this->getMonth(), $this->getDay()),
$this->_dateFormat
);
}
}
这个类提供了一些不错的扩展性--我们可以从我们的数据库中设置默认的值,同时确信值将会被保存而且正确的表现。另外,我们允许通过表单 input 用一个数组来传递值。最后,对于每一个日期片断,我们有了分离的访问器(accessors),我们现在可以把这些访问器应用在一个装饰器中,来创建一个合成元素。
装饰器
再看一下上一节提到的例子,让我们假设我们想让用户分别输入年,月,日。PHP 很幸运的允许我们在创建元素的时候使用数组表示法,所以它仍有可能采集这三个实体合成一个单一的值 -- 同时我们已经创建了一个 Zend_Form 元素可以处理这样一个数组。
装饰器相对简单:它会从元素抓取日,月和年,把每一个传递给一个分离视图帮助器来呈现个人的表单 input,然后这些会被合并,形成最后的标记(markup)。
class My_Form_Decorator_Date extends Zend_Form_Decorator_Abstract
{
public function render($content)
{
$element = $this->getElement();
if (!$element instanceof My_Form_Element_Date) {
// only want to render Date elements
return $content;
}
$view = $element->getView();
if (!$view instanceof Zend_View_Interface)
// using view helpers, so do nothing in no view present
return $content;
}
$day = $element->getDay();
$month = $element->getMonth();
$year = $element->getYear();
$name = $element->getFullyQualifiedName();
$params = array(
'size' => 2,
'maxlength' => 2,
);
$yearParams = array(
'size' => 2,
'maxlength' => 2,
);
$markup = $view->formText($name . '[day]', $day, $params)
. ' / ' . $view->formText($name . '[month]', $month, $params)
. ' / ' . $view->formText($name . '[year]', $year, $yearParams);
switch ($this->getPlacement()) {
case self::PREPEND:
return $markup . $this->getSeparator() . $content;
case self::APPEND:
default:
return $content . $this->getSeparator() . $markup;
}
}
}
我们现在得对我们的表单元素做一个小调整,告诉它我们想默认地使用上面的装饰器。这需要两个步骤。首先,我们需要把装饰器的路径通知这个元素。我们可以在构造函数中完成:
class My_Form_Element_Date extends Zend_Form_Element_Xhtml
{
// ...
public function __construct($spec, $options = null)
{
$this->addPrefixPath(
'My_Form_Decorator',
'My/Form/Decorator',
'decorator'
);
parent::__construct($spec, $options);
}
// ...
}
注意这些是在构造函数中完成,而不是在 init()。这有两个原因。首先,它允许以后在 init 扩展元素添加逻辑,而不必担心调用 parent::init()。其次,它允许通过设置(configuration)或者在一个 init 方法内传递额外的插件,然后允许用我自己的替代者来重写默认的日期装饰器。
下一步,我们需要使用我们新的日期装饰器来重写 loadDefaultDecorators() 方法:
class My_Form_Element_Date extends Zend_Form_Element_Xhtml
{
// ...
public function loadDefaultDecorators()
{
if ($this->loadDefualtDecoratorsIsDisabled()) {
return;
}
$decorators = $this->getDecorators();
if ($empty($decorators)) {
$this->addDecorator('Date')
->addDecorator('Errors')
->addDecorator('Description', array(
'tag' => 'p',
'class' => 'description'
))
->addDecorator('HtmlTag', array(
'tag' => 'dd',
'id' => $this->getName() . '-element'
))
->addDecorator('Label', array('tag' => 'dt'));
}
}
// ...
}
最后的输出是什么样子的?让我们想一下下面的元素:
$d = new My_Form_Element_Date('dateOfBirth');
$d->setLabel('Date of Birth: ')
->setView(new Zend_View());
// There are equivalent:
$d->setValue('20 April 2009');
$d->setValue(array('year' => '2009', 'month' => '04', 'day' => '20'));
如果你之后输出这个元素,你会得到下面的标记(markup)(对空格已经做过修改以便更好的阅读):
<dt id="dateOfBirth-label"><labe for="dateOfBirth" class="optional">
Date of Birth:
</label></dt>
<dd id="dateOfBirth-element">
<input type="text" name="dateOfBirth[day]" id="dateOfBirth-day"
value="20" size="2" maxlength="2"> /
<input type="text" name="dateOfBirth[month]" id="dateOfBirth-month"
value="4" size="2" maxlength="2"> /
<input type="text" name="dateOfBirth[year]" id="dateOfBirth-year"
value="2009" size="4" maxlength="4">
</dd>
<div class="element">
<?php echo $form->dateOfBirth->renderLabel(0 ?>
<?php echo $this->formText('dateOfBirth[day]', '', array('size' => 2, 'maxlength' =>2)) ?>
/
<?php echo $this->formText('dateOfBirth[month]', '', array('size' => 2, 'maxlength' =>2)) ?>
/
<?php echo $this->formText('dateOfBirth[year]', '', array('size' => 4, 'maxlength' => 4)) ?>
</div>
你如何把这个元素当作一个 Zend_Form_Element 来展现?你如何写一个装饰器来呈现它?
元素
元素是如何工作的,这个问题包括:
你如何设置和检索值?
你如何验证值?
不管其它的,你如何允许分离的表单 input 接受这三个片断(日,月,年)?
头两个问题围绕表单元素它自己:setValue() 和 getValue() 是如何工作的?事实上由这个问题可以暗示到关于装饰器的一个问题:你如何检索从元素得来的分离的数据片断以及/或者设置它们?
解决的办法是重写你的元素的 setValue() 方法来提供一些定制的逻辑。在这个特定的例子,我们的元素应该有三个分离的行为:
如果提供一个整型的时间戳,它应该被用作确定和储存日,月和年。
如果提供一个文字字符串,它应该能被转换成一个时间戳,然后这个值会用作确定和储存日,月和年。
如果提供一个包括日,月和年为键值的数组,那些值将会被储存。
内部的,日,月和年将被分别储存。当元素的值被检索到的时候,它将以一种规范化的字符串格式储存。我们重写 getValue() 也把分离的数据片断组合进一个最终的字符串。
我们的类将看起来是这样的:
class My_Form_Element_Date extends Zend_Form_Element_Xhtml
{
protected $_dateFormat = '%year%-%month%-%day%';
protected $_day;
protected $_month;
protected $_year;
public function setDay($value)
{
$this->_day = (int) $value;
return $this;
}
public function getDay()
{
return $this->_day;
}
public function setMonth($value)
{
$this->_month = (int) $value;
return $this;
}
public function getMonth()
{
return $this->_month;
}
public function setYear($value)
{
$this->_year = (int) $value;
return $this;
}
public function getYear()
{
return $this->_year;
}
public function setValue($value)
{
if (is_int($value)) {
$this->setDay(date('d', $value))
->setMonth(date('m', $value))
->setYear(date('Y', $value));
} elseif (is_string($value)) {
$date = strtotime($value);
$this->setDay(date('d', $date))
->setMonth(date('m', $date))
->setYear(date('Y', $date));
} elseif (is_array($value)
&& (isset($value['day'])
&& isset($value['month'])
&& isset($value['year'])
)
) {
$this->setDay($value['day'])
->setMonth($value['month'])
->setYear($value['year']);
} else {
throw new Exception('Invalid date value provided');
}
return $this;
}
public function getValue()
{
return str_replace(
array('%year%', '%month%', '%day%'),
array($this->getYear(), $this->getMonth(), $this->getDay()),
$this->_dateFormat
);
}
}
这个类提供了一些不错的扩展性--我们可以从我们的数据库中设置默认的值,同时确信值将会被保存而且正确的表现。另外,我们允许通过表单 input 用一个数组来传递值。最后,对于每一个日期片断,我们有了分离的访问器(accessors),我们现在可以把这些访问器应用在一个装饰器中,来创建一个合成元素。
装饰器
再看一下上一节提到的例子,让我们假设我们想让用户分别输入年,月,日。PHP 很幸运的允许我们在创建元素的时候使用数组表示法,所以它仍有可能采集这三个实体合成一个单一的值 -- 同时我们已经创建了一个 Zend_Form 元素可以处理这样一个数组。
装饰器相对简单:它会从元素抓取日,月和年,把每一个传递给一个分离视图帮助器来呈现个人的表单 input,然后这些会被合并,形成最后的标记(markup)。
class My_Form_Decorator_Date extends Zend_Form_Decorator_Abstract
{
public function render($content)
{
$element = $this->getElement();
if (!$element instanceof My_Form_Element_Date) {
// only want to render Date elements
return $content;
}
$view = $element->getView();
if (!$view instanceof Zend_View_Interface)
// using view helpers, so do nothing in no view present
return $content;
}
$day = $element->getDay();
$month = $element->getMonth();
$year = $element->getYear();
$name = $element->getFullyQualifiedName();
$params = array(
'size' => 2,
'maxlength' => 2,
);
$yearParams = array(
'size' => 2,
'maxlength' => 2,
);
$markup = $view->formText($name . '[day]', $day, $params)
. ' / ' . $view->formText($name . '[month]', $month, $params)
. ' / ' . $view->formText($name . '[year]', $year, $yearParams);
switch ($this->getPlacement()) {
case self::PREPEND:
return $markup . $this->getSeparator() . $content;
case self::APPEND:
default:
return $content . $this->getSeparator() . $markup;
}
}
}
我们现在得对我们的表单元素做一个小调整,告诉它我们想默认地使用上面的装饰器。这需要两个步骤。首先,我们需要把装饰器的路径通知这个元素。我们可以在构造函数中完成:
class My_Form_Element_Date extends Zend_Form_Element_Xhtml
{
// ...
public function __construct($spec, $options = null)
{
$this->addPrefixPath(
'My_Form_Decorator',
'My/Form/Decorator',
'decorator'
);
parent::__construct($spec, $options);
}
// ...
}
注意这些是在构造函数中完成,而不是在 init()。这有两个原因。首先,它允许以后在 init 扩展元素添加逻辑,而不必担心调用 parent::init()。其次,它允许通过设置(configuration)或者在一个 init 方法内传递额外的插件,然后允许用我自己的替代者来重写默认的日期装饰器。
下一步,我们需要使用我们新的日期装饰器来重写 loadDefaultDecorators() 方法:
class My_Form_Element_Date extends Zend_Form_Element_Xhtml
{
// ...
public function loadDefaultDecorators()
{
if ($this->loadDefualtDecoratorsIsDisabled()) {
return;
}
$decorators = $this->getDecorators();
if ($empty($decorators)) {
$this->addDecorator('Date')
->addDecorator('Errors')
->addDecorator('Description', array(
'tag' => 'p',
'class' => 'description'
))
->addDecorator('HtmlTag', array(
'tag' => 'dd',
'id' => $this->getName() . '-element'
))
->addDecorator('Label', array('tag' => 'dt'));
}
}
// ...
}
最后的输出是什么样子的?让我们想一下下面的元素:
$d = new My_Form_Element_Date('dateOfBirth');
$d->setLabel('Date of Birth: ')
->setView(new Zend_View());
// There are equivalent:
$d->setValue('20 April 2009');
$d->setValue(array('year' => '2009', 'month' => '04', 'day' => '20'));
如果你之后输出这个元素,你会得到下面的标记(markup)(对空格已经做过修改以便更好的阅读):
<dt id="dateOfBirth-label"><labe for="dateOfBirth" class="optional">
Date of Birth:
</label></dt>
<dd id="dateOfBirth-element">
<input type="text" name="dateOfBirth[day]" id="dateOfBirth-day"
value="20" size="2" maxlength="2"> /
<input type="text" name="dateOfBirth[month]" id="dateOfBirth-month"
value="4" size="2" maxlength="2"> /
<input type="text" name="dateOfBirth[year]" id="dateOfBirth-year"
value="2009" size="4" maxlength="4">
</dd>
相关文章推荐
- Zend Framework 1.10.1 理解和使用 Zend 表单装饰器之四:呈现独立装饰器
- Zend Framework 1.10.1 理解和使用 Zend 表单装饰器之一:介绍
- Zend Framework 1.10.1 理解和使用 Zend 表单装饰器之二:装饰器基础
- Zend Framework 1.10.1 理解和使用 Zend 表单装饰器之三:装饰器分层
- js创建表单元素并使用submit进行提交
- Zend Framework 1.10.1 开始使用 Zend_Search_Lucene
- 使用Pear QuickForm创建和验证表单2008-02-13 17:37这是Zend上的一篇文章 http://devzone.zend.com/article/2699-Generating-and-Validating-Web-Forms-Wit
- Zend Framework 1.10.1 开始使用 Zend_Session,Zend_Auth,和 Zend_Acl
- js创建表单元素并使用submit进行提交
- Zend Framework 1.10.1 开始使用 Zend_Search_Lucene
- Create RESTful Applications Using The Zend Framework(使用Zend Framework创建一个Restful应用)
- 使用 Zend_Form_Element 生成表单元素 --(手册)
- 使用Zend Framework中的 Zend_Pdf来创建pdf文档
- Zend Framework 1.10.1 快速入门之五:创建一个表单
- 一步步学习SPD2010--第八章节--理解工作流(2)--使用SPD创建工作流
- 一步步学习SPD2010--第九章节--使用可重用工作流和工作流表单(5)--创建全局可重用工作流
- Zend Framework使用Zend_Loader组件动态加载文件和类用法详解
- 使用HTML5和CSS3创建一个时髦的联系表单
- "黑马程序员"基础测试:创建ArrayList对象,添加五个元素,使用Iterator遍历输出
- 一步步学习微软InfoPath2010和SP2010--第五章节--添加逻辑和规则到表单(6)--使用规则创建多视图样式向导表单