`

Zend Framework 1.10.1 理解和使用 Zend 表单装饰器之五:创建和呈现复合元素

 
阅读更多

在上一节中,我们有一个展示一个出生日期元素的例子:

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

分享到:
评论

相关推荐

    libzip-1.10.1.tar.gz

    libzip的源代码和文档都是开放的,开发者可以通过阅读源码和官方文档深入理解其内部机制,以便更好地利用这个库。 总的来说,libzip库在1.10.1版本中不仅保持了原有的强大功能,还进一步优化了安全性、性能和易用性...

    jquery-ui-1.10.1.custom.zip

    - **主题构建器**: jQuery UI 允许用户通过在线主题构建器创建和定制自己的主题,满足不同项目的设计需求。 - **模块化设计**: 每个组件都是独立的模块,可以根据项目需求选择性加载,降低页面加载时间。 - **...

    svn 1.10.1

    1. 更直观的界面:所有的菜单、选项和提示都以中文呈现,易于理解和操作。 2. 支持中文文件名:对于包含中文字符的文件或目录,SVN能够正确处理和存储。 3. 更好的协作:团队成员可以更顺畅地交流,因为版本控制系统...

    synergy1.10.1.rar

    标题中的"synergy1.10.1.rar"是一个压缩包文件,其版本号为1.10.1,通常这种格式的文件是使用RAR压缩算法打包的,它可能包含了软件安装所需的所有文件。RAR是一种常见的文件压缩格式,由WinRAR软件创建,允许用户将...

    parquet-column-1.10.1-API文档-中文版.zip

    赠送jar包:parquet-column-1.10.1.jar; 赠送原API文档:parquet-column-1.10.1-javadoc.jar; 赠送源代码:parquet-column-1.10.1-...人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。

    jquery-1.10.1中文汉化二版

    jQuery 1.10.1是该库的一个重要版本,虽然现在已经有更新的版本,但1.10.1仍然在很多项目中被广泛使用,它的稳定性和兼容性得到了充分验证。 1. **基本用法**: jQuery的使用通常始于一个熟悉的$(document).ready...

    PyVISA-1.10.1_pyvisa_pyvisaSCPI_Pyvisa1.10.1_

    标题"PyVISA-1.10.1_pyvisa_pyvisaSCPI_Pyvisa1.10.1_"暗示了我们讨论的是PyVISA的1.10.1版本,同时提到了与`pyvisa`和`pyvisaSCPI`相关的元素。`pyvisa`是PyVISA的核心库,而`pyvisaSCPI`则是针对基于SCPI...

    heritrix-1.10.1

    例如,可以使用过滤器去除重复的URL,或者根据内容的某些特征(如元数据)进行筛选。 5. **可配置性与扩展性**:Heritrix 1.10.1版本可能包含一些特定的配置选项,使得用户能够调整其行为以满足具体项目需求。...

    hdf5-1.10.1.tar.gz

    HDF5(Hierarchical Data Format 5)是一种用于存储和管理大量复杂数据的开源文件格式。...对于开发者来说,理解和掌握HDF5的使用可以极大地提高数据处理和分析的效率,特别是在处理大规模科学数据或深度学习模型时。

    jquery-ui-1.10.1

    《jQuery UI 1.10.1:构建交互式网页的强大工具》 jQuery UI 是一个基于 jQuery JavaScript 库的开源项目,它提供了丰富的用户界面组件和交互效果,为开发者提供了构建功能丰富的、交互性强的网页应用的强大支持。...

    apache-ant-1.10.1

    3. **新的任务和元素**:可能引入了新的构建任务或者对已有任务进行了扩展,以适应更广泛的项目需求。 4. **更好的错误处理**:可能改进了错误报告和异常处理,帮助开发者更快地定位和解决问题。 5. **与Maven的兼容...

    parquet-hadoop-1.10.1-API文档-中文版.zip

    赠送jar包:parquet-hadoop-1.10.1.jar 赠送原API文档:parquet-hadoop-1.10.1-javadoc.jar 赠送源代码:parquet-hadoop-1.10.1-...人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。

    jquery1.10.1中文离线版文档CHM+在线版压缩包

    1. **选择器**:jQuery 的选择器是其强大之处,如 `$()` 可以选取元素,`$("#id")` 选取 ID 为 id 的元素,`$(".class")` 选取所有 class 为 class 的元素,`$("tag")` 选取所有 tag 元素。 2. **DOM 操作**:...

    jquery1.10.1

    《jQuery 1.10.1:开源代码与jQuery UI 1.10.1定制》 jQuery,作为一款广泛使用的JavaScript库,以其简洁的API和强大的功能深受开发者喜爱。1.10.1版本是jQuery历史上的一个重要里程碑,它在前一版本的基础上进行了...

    libpcap-1.10.1.tar.gz

    **libpcap 源码安装详解** libpcap 是一个强大的开源库,主要用于网络数据包...通过理解其工作原理和API,开发者可以创建各种自定义的网络监控解决方案。正确安装和使用libpcap,有助于提升网络运维的效率和安全性。

    SVN1.10.1安装包及汉化包

    SVN(Subversion)是一种广泛使用的版本控制系统,用于管理软件项目的源代码和其他文件。它允许开发者在团队中协作,跟踪每一次更改,同时提供回溯和恢复功能。SVN1.10.1是Subversion的一个特定版本,包含了若干增强...

    numpy-1.10.1.zip

    Numpy是Python编程语言中的一个核心库,专用于科学计算,尤其在处理多维数据时。这个"numpy-1.10.1.zip"文件是一个包含Numpy 1.10.1版本源代码的...正确安装和理解Numpy的特性是提升Python编程效率的关键步骤之一。

    apache-ant-1.10.1-bin.tar.gz

    3. `docs` 目录:包含Ant的用户手册和API文档,帮助开发者理解和使用Ant。 4. `LICENSE` 和 `NOTICE` 文件:提供了关于Apache Ant的许可信息和版权声明。 5. `README` 文件:通常提供快速安装指南和其他重要信息。在...

    jQuery1.10.1.zip最新版

    1. **选择器引擎Sizzle**:jQuery使用Sizzle选择器引擎,能够解析CSS1至CSS3的选择器,使开发者可以方便地通过链式语法选取DOM元素。 2. **DOM操作**:包括添加、删除、复制、移动DOM元素,以及查找和操作子元素。...

Global site tag (gtag.js) - Google Analytics