CakePHP中文手册【翻译】-Helper

Helper

1

Helper

Helper意为着提供许多函数,这些函数通常用在view中,并以一种有用的方式格式化并展示数据。

HTML

介绍

HTML HelperCake的一种让开发不再那么枯燥,并且变得更加快速的方法。HTML Helper2个目标:帮助插入HTML代码中经常重复的部分,并致力于快速简单创建Web表单。下面的章节将为你介绍最重要的Helper函数,但是记住使用http://api.cakephp.org作为最终的参考。

HTML Helper的许多函数使用了HTML标签定义文件,此文件为tags.ini.php.Cake核心的配置文件包含了一个tags.ini.php,但是如果你想做出一些修改,拷贝一份/cake/config/tags.ini.php,并将它放在/app/config/ 文件夹下。HTML Helper在文件里使用标签定义来生成你请求的标签。使用HTML Helper来创建某些view代码是有帮助的,因为一个tags.ini.php文件的修改会导致一个站点级的变化。

除此之外,在应用程序的核心配置文件(/app/config/core.php)里,如果AUTO_OUTPUT设置为trueHelper会自动输出标签,而不是返回其值。通过努力,已经实现它来减轻那些厌恶在他们view代码里调用短标签(<?= ?>)或许多echo()的痛楚。包含$return参数的函数允许你强制覆写核心配置的设置。如果你想HTML Helper返回HTML代码而与AUTO_OUTPUT的任何设置无关,将$return设置为true

HTML Helper函数也包含参数$htmlAttributes,此参数允许你跟踪标签上的额外属性。例如,如果你有一个标签,并且你想为它增加一个class属性,你可以将它作为$htmlAttribute值传入:

array('class'=>'someClass')

插入格式好了的元素

如果你想使用CakeHTML代码里插入格式化好了的,并且经常重复的元素,HTML Helper最擅长做这件事情了。在helper里有很多函数插入媒体,并帮助处理表。甚至有guiListTree来创建一个无序的基于PHP数组的列表。

charset

  • string $charset
  • boolean $return

用来生成一个字符集的META标签。

css

  • string $path
  • string $rel = 'stylesheet'
  • array $htmlAttributes
  • boolean $return = false

$rel参数允许你为标签提供一个rel=的值。

创建一个CSS样式的链接。

image

  • string $path
  • array $htmlAttributes
  • boolean $return = false

Render一个图像标签。函数返回的代码可以做为一个link()函数的输入框来自动创建链接的图像。

link

  • string $title
  • string $url
  • array $htmlAttributes
  • string $confirmMessage = false
  • boolean $escapeTitle = true
  • boolean $return = false

view里使用本函数创建链接。当点击链接后,如果你需要显示一个JavaScript确认消息时,使用$confirmMessage吧。例如,在链接启用之前,点击一个删除对象的链接可能会跳出一个"Are you sure?"消息来确认动作。如果你想让HTML Helper跳出你在$title变量里设置的数据,将$escapeTitle设置为true

tableHeaders

  • array $names
  • array $tr_options
  • array $th_options

使用一个格式化的表头。

tableCells

  • array $data
  • array $odd_tr_options
  • array $even_tr_options

用来创建一组格式化的表单元格。

guiListTree

  • array $data
  • array $htmlAttributes
  • string $bodyKey = 'body'
  • string $childrenKey = 'children'
  • boolean $return = false

从数组里生成一个无序嵌套的列表树。

表单和验证

在你的view里,当HTML Helper想加速你的表单代码时,这时它表现的非常耀眼。它会生成所有的表单标记,在错误的环境下会自动填充值,并会指出错误信息。为了帮助表述,让我们过一遍一个快速的实例。假设一会应用程序有一个Note model,并且你想创建controller逻辑和一个view来增加和编辑Note对象。在NotesController,你会有一个edit动作,可能如下:

NotesController内的编辑动作

   function edit($id)
   {
      //First, let's check to see if any form data has been
      //submitted to the action.
      if (!empty($this->data['Note']))
      {
         //Here's where we try to validate the form data (see Chap. 12)
         //and save it
         if ($this->Note->save($this->data['Note']))
         {
            //If we've successfully saved, take the user
            //to the appropriate place
            $this->flash('Your information has been saved.', '/notes/edit/' . $id);
            exit();
         }
         else
         {
 
            //Generate the error messages for the appropriate fields
            //this is not really necessary as save already does this, but it is an example
            //call $this->Note->validates($this->data['Note']); if you are not doing a save
            //then use the method below to populate the tagErrorMsg() helper method
            $this->validateErrors($this->Note);
 
            //And render the edit view code
            $this->render();
         }
      }
 
      // If we haven't received any form data, get the note we want to edit, and hand
      // its information to the view
      $this->set('note', $this->Note->find("id = $id"));
      $this->render();
   }

一旦我们建立了controller,让我们看看view代码(在app/views/notes/edit.thtml). 在这里,我们的Note Model非常简单,因为它仅仅包含了一个id,一个提交者的id,以及一个bodyview代码会显示Note数据,并允许用户输入新的值,然后将数据保存到model里。

缺省的,HTML Helper在所有view都是可用的,我们可以使用$html来访问它。

特别的,让我们看看表,表单的核心就在这里

 

编辑View (edit.thtml)代码实例

<!-- This tag creates our form tag -->
 
<?php echo $html->formTag('/notes/edit/' . $html->tagValue('Note/id')?>
 
<table cellpadding="10" cellspacing="0">
<tr>
   <td align="right">Body: </td>
   <td>
 
      <!-- Here's where we use the HTML helper to render the text
           area tag and its possible error message the $note
           variable was created by the controller, and contains
           the data for the note we're editing. -->
      <?php echo
      $html->textarea('Note/body', array('cols'=>'60', 'rows'=>'10'));
      ?>
      <?php echo $html->tagErrorMsg('Note/body',
      'Please enter in a body for this note.') ?>
   </td>
</tr>
<tr>
   <td></td>
   <td>
 
      <!-- We can also use the HTML helper to include
           hidden tags inside our table -->
 
      <?php echo $html->hiddenTag('Note/id')?>
      <?php echo $html->hiddenTag('note/submitter_id', $this->controller->Session->read('User.id'))?>
   </td>
</tr>
</table>
 
<!-- And finally, the submit button-->
<?php echo $html->submit()?>
 
</form>

大多数表单标记生成函数(与tagErrorMsg一起)需要提供$fieldName$fieldNameCake知道你传递哪些数据,使它能正确保存并验证这些数据。传递给$fieldName参数的字符串以"Model名(modelname/字段名(fieldname"的格式来传递。

如果你正想增加一个标题的字段到我们的Note中,你需要增加一些东东到View中,像下面这样:

<?php echo $html->input('Note/title') ?>
<?php echo $html->tagErrorMsg('Note/title', 'Please supply a title for this note.')?>

tagErrorMsg()函数显示的错误信息包含在<div class="error_message"></div>,并有简单的CSS样式。

下面是HTML Helper可以生成的表单标签(tag)(他们大多数都是非常明了的):

submit

  • string $buttonCaption
  • array $htmlAttributes
  • boolean $return = false

password

  • string $fieldName
  • array $htmlAttributes
  • boolean $return = false

textarea

  • string $fieldName
  • array $htmlAttributes
  • boolean $return = false

checkbox

  • string $fieldName
  • array $htmlAttributes
  • boolean $return = false

file

  • string $fieldName
  • array $htmlAttributes
  • boolean $return = false

hidden

  • string $fieldName
  • array $htmlAttributes
  • boolean $return = false

input

  • string $fieldName
  • array $htmlAttributes
  • boolean $return = false

radio

  • string $fieldName
  • array $options
  • array $inbetween
  • array $htmlAttributes
  • boolean $return = false

tagErrorMsg

  • string $fieldName
  • string $message

HTML Helper同时也包含一组函数,这些函数帮助创建与日期相关的选项标签。$tagName参数应该当成$fieldName参数以同样的方式来处理。仅提供日期选项标签相关的字段名称。一旦数据被处理,你会在你的Controller里看见它。此Controller包含它处理的日期部分,并且在字段名结尾处连接。例如,如果Note有一个日期类型的截止日期(Deadline)字段,那么dayOptionTag $tagName参数应设置为'note/deadline',一旦将表单提交到一个controller动作里,日期数据会在$params参数里显示:

$this->data['Note']['deadline_day']

然后你能使用此信息以一种格式连接时间数据,此格式对当前数据库配置来说是友好的。本代码仅在你打算保存数据之前才放入的,将它保存到一个$data数组,此数组用来将信息保存到model中。

在保存model之前链接时间数据(摘录自NotesController

function edit($id)
   {
      //First, let's check to see if any form data has been submitted to the action.
      if (!empty($this->data['Note']))
      {
 
         //Concatenate time data for storage...
         $this->data['Note']['deadline'] =
            $this->data['Note']['deadline_year'] . "-" .
            $this->data['Note']['deadline_month'] . "-" .
            $this->data['Note']['deadline_day'];
 
         //Here's where we try to validate the form data (see Chap. 10) and save it
         if ($this->Note->save($this->data['Note']))
         {
            ...

1.    dayOptionTag ($tagName, $value=null, $selected=null, $optionAttr=null)

2.    yearOptionTag ($tagName, $value=null, $minYear=null, $maxYear=null, $selected=null, $optionAttr=null)

3.    monthOptionTag ($tagName, $value=null, $selected=null, $optionAttr=null)

4.    hourOptionTag ($tagName, $value=null, $format24Hours=false, $selected=null, $optionAttr=null)

5.    minuteOptionTag ($tagName, $value=null, $selected=null, $optionAttr=null)

6.    meridianOptionTag ($tagName, $value=null, $selected=null, $optionAttr=null)

7.    dateTimeOptionTag ($tagName, $dateFormat= 'DMY', $timeFormat= '12', $selected=null, $optionAttr=null)

AJAX

为了Ajax操作和客户端效果,CakeAjax Helper利用了曾经流行的Prototypescript.aculo.us库。为使用这个Helper,你必须从http://script.aculo.us得到一个当前版本的JavaScript库,并将它放在/app/webroot/js/这个地方。除此之外,任何计划使用Ajax HelperView需要包含这些库。

Helper的大多数函数需要有一个特定的$options数组作为参数。本数组用来指定关于Ajax操作的不同东西。下面是可以制定的不同值:

AjaxHelper $options

/* 一般选项*/

 

$options['url']         //你想用来调用的动作(ActionURL

$options['frequency']   //remoteTimer()observeField()检查的间隔秒             

 

$options['update']      // 你希望用来更新Ajax操作结果的元素的DOM ID

 

$options['with']        //你希望用来序列化而且随一个Ajax表单提交的表单元素 DOM ID

 

$options['type']        // 要么是'asynchronous' (缺省),或是 'synchronous'.

//允许选择一个操作类型

                    

/* 回调 : XMLHttpRequest 处理过程中在某次数上执行的JS代码*/

 

$options['loading']    //当浏览器加载远程数据时执行的JS 代码

 

$options['loaded']      //当浏览器正完成加载远程文档时执行的JS 代码。

 

$options['interactive'] // 当用户可以和远程文档交互,甚至没有完成加载时执行的JS编码。

 

$options['complete']    //完成时调用的JS编码。

 

$options['confirm']     //在一个XMLHttpRequest动作开始之前在确认对话框显示的文本。

 

$options['condition']   // XMLHttpRequest启动之前需要符合的JS条件。

 

$options['before']      //请求启动前调用的JS编码

 

$options['after']       //在请求启动后,加载前理解调用的JS编码

下面的Helper函数使CakeAjax变得更加快速而且简单:

link

  • string $title
  • string $href
  • array $options
  • boolean $confirm
  • boolean $escapeTitle

显示链接文本$title,它获取$options['url']的远程文档,并且更新DOM元素$options['update'].回调可以和本函数一起使用。

remoteFunction

  • array $options

本函数创建一个远程调用需要的JavaScript。为linkToRemote,它主要作为一个Helper。它不会常常使用,除非你需要生成一些自定义的脚本。

remoteTimer

  • array $options

周期性的调用在$options['url']中指定的动作,周期是每$options['frequency']秒(缺省为10)。通常用来更新一个指定的带有远程调用结果的div(由$options['update']指定)。回调可以和本函数一起使用。

form

  • string $action
  • string $type
  • array $options

返回一个表单,本表单提交到$action动作,在后台使用XMLHttpRequest代替常规的重加载POST提交。本表单的数据仅扮演一个正常的表单数据角色,(例如,可以在$this->params['form']获取)。$options['update']指定的DOM元素会更新为受影响的远程文档。回调可以和本函数一起使用。

observeField

  • string $field_id
  • array $options

观察$field_id指定的DOM ID字段(每$options['frequency']秒),并当他的内容改变时调用$options['url']的动作。你也可以更新IDD $options['update']DOM元素,或指定一个也使用$options['with']的表单元素。回调可以和本函数一起使用。

observeForm

  • string $form_id
  • array $options

observeField()一样。它仅观察给定表单的所有元素。

autoComplete

  • string $field
  • string $url
  • array $options

自动完成renderID$field的文本字段。$url的动作应该可以返回autocomplete条件:基本上,你的动作需要取消一个无序列表(<ul></ul>),此列表有一些自动完成的条件。如果你想要一个获取Blog Post主题的autocomplete字段,Controller动作可以如下:

function autocomplete () 
{
    $this->set('posts',
        $this->Post->findAll(
            "subject LIKE '{$this->data['Post']['subject']}'")
        );
    $this->layout = "ajax";
}

上面autocomplete()动作对应的view可以如下:

<ul>
<?php foreach($posts as $post): ?>
<li><?php echo $post['Post']['subject']; ?></li>
<?php endforeach; ?>
</ul>

View里实际看到的自动完成(auto-complete)字段应该如下:

<form action="/users/index" method="POST">
    <?php echo $ajax->autoComplete('Post/subject', '/posts/autoComplete')?>
    <?php echo $html->submit('View Post')?>
</form>

autoComplete()函数使用本信息render一个文本字段,以及一些用来展示动作提供的autocomplete条件的div。你也可能想将view打扮成下面这样:

<style type="text/css">
 
div.auto_complete {
    position         :absolute;
    width            :250px;
    background-color :white;
    border           :1px solid #888;
    margin           :0px;
    padding          :0px;
}
 
li.selected { background-color: #ffb; }
 
</style>

drag

  • string $id
  • array $options

使ID $id DOM元素可以拖拽。你需要在$options里指定一些附加的信息:

// (版本号参考script.aculo.us版本)

$options['handle']     // (v1.0)设置作为一个嵌入的处理元素是否仅可以拖拽。//本值必须为一个元素的引用或者元素的ID

 

$options['handle']     // (V1.5)和上面一样,除了当前值可以是一个引用了一个CSS class值的字符串。第一个child/grandchild/etc可以在有本CSS class值的元素中找到,此CSS作为句柄来使用了。

 

$options['revert']     // (V1.0)如果设置为true,当拖拽结束时元素返回它的原始位置。

 

$options['revert']     // (V1.5)撤销也可以为一个任意的函数引用,当拖拽结束时调用。

 

$options['constraint'] // 如果设置为horizontal(水平)或 vertical(垂直),拖拽会受限,仅仅在水平或垂直上发生。

drop

  • string $id
  • array $options

使ID$id DOM元素可以下拉。你可以在$options里指定一些附加的信息:

$options['accept']      //. accept设置为一个字符串或者一个描述CSS class JavaScript的字符串数组。Droppable仅接受Draggable,此Draggable有这些CSS class的一个或多个。

 

$options['containment'] //如果它包含在给定元素(或者元素id)中,可下拉的元素仅接受可下拉的元素。可以是单个,也可以是一个元素的JS数组。

 

$options['overlap']     //如果设置为orizontal(水平)或 vertical(垂直),,如果在给定方向超过50%的重复,可下拉的元素仅对可下拉的元素有反应。

dropRemote

  • string $id
  • array $options
  • array $ajaxOptions

用来创建一个下拉目标,当一个拖拽的元素可以在它之上下拉时,它会启动一个XMLHttpRequest请求。$optionsdrop()一样,而且$ajaxOptionslink()相同。

sortable

  • string $id
  • array $options

使一组浮动的对象(ID$idDOM 元素指定)组或列表变得有序。$options数组可以如下配置你的排序:

$options['tag']         // 设置为排序的标签(或者容器里的子元素)。对于OL容易,它是LI,你必须为其他子标签提供标签种类,且省为’li’.

 

$options['only']        //进一步限制子元素的选择,仅选取那些给定CSS class的元素(或者,如果你提供了一个字符串的数组,选择任何CSS class的那些元素)。

 

$options['overlap']     // vertical(缺省)或者 horizontal,对于浮动的有序对象或水平列表,选择horizontal。垂直列表应该是vertical

 

$options['constraint']  //将可拖拽的元素移动限制为'vertical' 'horizontal'

 

$options['containment'] // 启用Sortable间的拖拽和下拉。使用一组元素或元素id(容器里的)

 

$options['handle']      //使创建的可拖拽的元素使用句柄,参看drag()handle选项。

editor

  • string $id
  • string $url
  • array $options

IDidDOM元素作第一个参数来创建一个内建的Ajax编辑器。实现之后,mouseOver时元素会突出,当点击时,会变为一个文本输入框。第二个参数是一个编辑的数据发送到此的URL。动作也可以返回一个已更新的元素内容。编辑器的其他附加选项可以在Script.aculo.uswiki里找到。

Javascript

JavaScript Helper用来帮助开发人员输出优秀格式的与JavaScript相关的标签和数据。

codeBlock

  • string $string

返回JavaScript <script>标签里的$script

link

  • string $url

返回一个JavaScript include标签,它指向引用$url的脚本。

linkOut

  • string $url

link()相同,include标签仅假定引用$url的脚本不再相同的域上。

escapeScript

  • string $script

忽略JavaScript代码的回车,单引号和双引号。

event

  • string $object
  • string $event
  • string $observer
  • boolean $useCapture

将一事件加到一个元素上。和Prototype库一起使用。

  • cacheEvents

缓存event()创建的的JavaScript事件。

  • writeEvents

写入cacheEvents()缓存的事件。

includeScript

  • string $script

数字

数字Helper包含了一些非常优秀的函数来格式化View的数字。

precision

  • mixed $number
  • int $precision = 3

返回格式化到$precision指定的精确度的$number

toReadableSize

  • int $sizeInBytes

返回一个可读的大小,假定$size以字节提供。

基本上,你传入一字节数,本函数返回一个合适的可读的KB, MB, GB,TB值。

toPercentage

  • mixed $number
  • int $precision = 2

返回格式化为百分数的数字,并精确到$precision

文本

Text Helper提供一些方法供开发人员将优秀格式化好的文本输出到浏览器。

highlight

  • string $text
  • string $highlighter = '<span class="highlight">\1</span>'

返回$text,带有此文本每个出现的地方或$phrase ,它们都在$highlighter指定的标签中。

stripLinks

  • string $text

返回已删除所有HTML链接(<a href=…)的$text

autoLinkUrls

  • string $text
  • array $htmlOptions

返回包含对应的<a>标签中的URL$text

autoLinkEmails

  • string $text
  • array $htmlOptions

返回包含在相应<a>标签中的邮件地址的$text

autoLink

  • string $text
  • array $htmlOptions

返回包含在相应的<a>标签中的URLemail

truncate

  • string $text
  • int $length
  • string $ending = '...'

返回第一个$text 中的$length数量的字符,并且$text紧跟$ending (缺省'...' )。的

excerpt

  • string $text
  • string $phrase
  • int $radius = 100
  • string $ending = '...'

解析一个对$text的引用,在每边的$radius范围内抓取一定数量字符的$phrase

autoLinkEmails

  • string $text
  • boolean $allowHtml = false

文本到HTML的解析器,和TextileRedCloth有点类似,仅仅是语法有一点不同。

时间

时间Helper提供方法让开发人员将Unix时间戳和/或日期时间字符串格式化为更加利于理解的格式并输出到浏览器。

可以将时间以有效PHP时间字符串或Unix时间戳提供给所有函数。

fromString

  • string $dateString

如果给定一个UNIX时间戳或一个有效的strtotime()日期字符串,返回一个UNIX时间戳。

nice

  • string $dateString
  • boolean $return = false

返回一个格式化非常好的日期字符串。日期格式为"D, M jS Y, H:i", 'Mon, Jan 1st 2005, 12:00'.

niceShort

  • string $dateString
  • boolean $return = false

格式话如nice()指定的日期字符串,但是如果字符串是今天,却输出"Today, 12:00",如果字符串是昨天,却输出"Yesterday, 12:00"

isToday

  • string $dateString

如果给定的日期字符串是今天,则返回true

daysAsSql

  • string $begin
  • string $end
  • string $fieldName
  • boolean $return = false

返回一个局部的SQL字符串来查询所有在这2个日期之间的记录。

dayAsSql

  • string $dateString
  • string $fieldName
  • boolean $return = false

返回一个局部SQL字符串来查询所有发生在同一天而且在这2个时间的记录。

isThisYear

  • string $dateString
  • boolean $return = false

如果给定的日期是在当年,返回true

wasYesterday

  • string $dateString
  • boolean $return = false

如果给定的日期是在昨天,返回true

isTomorrow

  • string $dateString
  • boolean $return = false

如果给定的日期是在明天,返回true

toUnix

  • string $dateString
  • boolean $return = false

返回一个文本时间描述的UNIX时间戳,一个对PHP函数strtotime()的包装。

toAtom

  • string $dateString
  • boolean $return = false

Atom RSS feed返回一个格式化的日期。

toRSS

  • string $dateString
  • boolean $return = false

RSS feed格式化日期。

timeAgoInWords

  • string $dateString
  • boolean $return = false

返回一个相对日期或者一个格式化的日期,此日期取决于当前时间和给定时间的差。$datetime的格式应该是strtotime()可解析的,像MySQL的时间。

relativeTime

  • string $dateString
  • boolean $return = false

timeAgoInWords()非常类似,但是它有能力为未来的时间戳创建输出(例如,"Yesterday, 10:33", "Today, 9:42", 以及 "Tomorrow, 4:34").

relativeTime

  • string $timeInterval
  • string $dateString
  • boolean $return = false

如果指定的时间在指定的间隔内,返回true,否则返回false。时间间隔应该以数字的格式指定,单位也是:'6 hours', '2 days'等。

Cache

2

创建自己的Helper

在你的view代码中,是否需要一些帮助?如果你发现你自己不断的需要某些特定的view逻辑,你可创建你自己的view helper

假设我们想创建一个helper,它可以用来输出一个应用程序中使用的CSS格式的链接。为了让你的逻辑合适Cake已存在的Helper结构,你需要在/app/views/helpers创建一个新类。让我们称我们的helperLinkHelper吧。实际的PHP类文件如下:

/app/views/helpers/link.php

class LinkHelper extends Helper

{

    function makeEdit($title, $url)

    {

        // Logic to create specially formatted link goes here...

    }

}

你可能需要利用在Cake Helper类里包含的一些函数:

output

  • string $string
  • boolean $return = false

决定是否输出或返回一个基于AUTO_OUTPUT(参看/app/config/core.php)$return值的字符串。你应该使用此方法将所有数据返回到view里。

  • loadConfig

返回应用程序当前核心的配置以及标签定义。

使用output()格式化我们链接标题以及URL,并将它返回给view

/app/views/helpers/link.php (增加了逻辑)

class LinkHelper extends Helper

{

    function makeEdit($title, $url)

    {

        // Use the helper's output function to hand formatted

        // data back to the view:

 

        return $this->output("<div class=\\"editOuter\\"><a href=\\"$url\\" class=\\"edit\\">$title</a></div>");

    }

}

包含其他Helper

你可能想使用在其他helper中已经存在的功能。为了利用他们,你可以在$helper数组里指定你想使用的helper,和你在controller的格式一样.

/app/views/helpers/link.php (使用其他helpers)

class LinkHelper extends Helper

{

 

    var $helpers = array('Html');

 

    function makeEdit($title, $url)

    {

        // Use the HTML helper to output

        // formatted data:

 

        $link = $this->Html->link($title, $url, array('class' => 'edit'));

 

        return $this->output("<div class=\\"editOuter\\">$link</div>");

    }

}

使用自定义的Helper

一旦你已经创建了一个helper,而且将它放入/app/views/helpers/,你需要通过特殊的$helper变量将它包含在你的controller里,

class ThingsController

{

    var $helpers = array('Html', 'Link');

}

如果你计划在其他地方使用它时,记住包含数组中的HTML helper。命名过则和model的类似。

1.    LinkHelper =类名

2.    Helper数组里的link = key

3.    link.php =/app/views/helpers中的PHP文件名

捐献

请考虑一下给Cake的代码-使用Trac系统或邮件列表联系一个开发人员,或创建一个新的CakeForge项目,和其他人共享你的新Helper

Last Updated:2006-12-03
posted @ 2006-11-22 22:32  张太国  阅读(4410)  评论(0编辑  收藏  举报