采用版本Joomla1.5、
第一步,在administrator/components/下建立com_reviews文件夹,然后创建toolbar.reviews.html.php
代码如下:
<?php defined(‘_JEXEC‘ )or die(‘Restricted access‘ ); class TOOLBAR_reviews{ function _NEW(){ JToolBarHelper::save(); JToolBarHelper::apply(); JToolBarHelper::cancel(); } function _DEFAULT(){ JToolBarHelper::title(JText::_(‘Restaurant Reviews‘),‘generic.png‘); JToolBarHelper::publishList(); JToolBarHelper::unpublishList(); JToolBarHelper::editList(); JToolBarHelper::deleteList(); JToolBarHelper::addNew(); } } ?> |
第二步,在administrator/components/下建立com_reviews文件夹,然后创建toolbar.reviews.php,代码如下
<?php defined(‘_JEXEC‘ )or die(‘Restricted access‘ ); require_once(JApplicationHelper::getPath(‘toolbar_html‘)); switch($task){ case ‘edit‘: case ‘add‘: TOOLBAR_reviews::_NEW(); break; default: TOOLBAR_reviews::_DEFAULT(); break; } ?> |
以上代码是希望得到以下效果:
可是输入以下url无法显示,报出404页面,http://localhost/joomla/administrator/index.php?option=com_reviews
先不管,继续做下去,
第三步,创建数据库表
CREATE TABLE `jos_reviews`( `id`int(11)NOT NULL auto_increment, `name`varchar(255)NOT NULL, `address`varchar(255)NOT NULL, `reservations`varchar(255)NOT NULL, `quicktake` textNOT NULL, `review` textNOT NULL, `notes` textNOT NULL, `smoking` tinyint(1) unsignedNOT NULL default ‘0‘, `credit_cards`varchar(255)NOT NULL, `cuisine`varchar(31)NOT NULL, `avg_dinner_price` tinyint(3) unsignedNOT NULL default ‘0‘, `review_date` datetimeNOT NULL, `published` tinyint(1) unsignedNOT NULL default ‘0‘, PRIMARY KEY(`id`) ) ENGINE=MyISAMDEFAULT CHARSET=utf8; |
第四步,既然创建了数据库表,那么接下来自然而然就创建数据库表类,在 administrator/components/com_reviews 文件夹下,创建一个 tables 文件夹,然
后在里面创建 review.php 文件并输入一下代码:
<?php defined(‘_JEXEC‘)or die(‘Restricted access‘); //修改前class TableRevies extends JTable<br> class TableReview extends JTable{ var $id = null; var $name = null; var $address = null; var $reservations = null; var $quicktake = null; var $review = null; var $notes = null; var $smoking = null; var $credit_cards = null; var $cuisine = null; var $avg_dinner_price = null; var $review_date = null; var $published = null; function __construct(&$db){ parent::__construct(‘#__reviews‘,‘id‘,$db); } } ?> |
我们继承了 JTable 类,并加入数据表的所有字段作为类的成员变量,成员变量都初始化为 null。然后覆盖类的构造函数 __construct() ,__construct() 会带有一个数据库对象为参数,并调用父类的构造函数,以数据表名(以#__为前缀)、主键和数据库对象为参数值。
说明:为什么要使用 #__ 为数据表的前缀?
在 Joomla!编写查询和定义 JTable 扩展时,使用 #__ 代替 jos_。Joomla! 执行查询时会自动将 #__ 替换为 管理员选择的数据库前缀。 这样的好处是可以在同一个数据库中运行多套Joomla!。你随便修改数据库的前缀也不用修改代码。TableReview 类继承了 bing()、store()、load() 和 delete() 等函数,这四个函数可以让你不用写一行的 SQL 就可以管理数据库的记录。
第五步,创建好了数据表,我们需要有一个友好的界面来增加点评。添加admin.reivews.php,代码如下:
<?php defined(‘_JEXEC‘)or die(‘Restricted access‘); require_once(JApplicationHelper::getPath(‘admin_html‘)); JTable::addIncludePath(JPATH_COMPONENT.DS.‘tables‘); switch($task){ case ‘add‘: editReview($option); break; } function editReview($option){ $row = &JTable::getInstance(‘Review‘,‘Table‘); $lists =array(); $reservations =array( ‘0‘=>array(‘value‘=>‘None Taken‘,‘text‘=>‘None Taken‘), ‘1‘=>array(‘value‘=>‘Accepted‘,‘text‘=>‘Accepted‘), ‘2‘=>array(‘value‘=>‘Suggested‘,‘text‘=>‘Suggested‘), ‘3‘=>array(‘value‘=>‘Required‘,‘text‘=>‘Required‘) ); $lists[‘reservations‘] = JHTML::_(‘select.genericList‘,$reservations,‘reservations‘,‘class="inputbox"‘.‘‘,‘value‘,‘text‘,$row->reservations); $lists[‘smoking‘] = JHTML::_(‘select.booleanlist‘,‘somking‘,‘class="inputbox"‘,$row->smoking); $lists[‘published‘] = JHTML::_(‘select.booleanlist‘,‘published‘,‘class="inputbox"‘,$row->published); HTML_reviews::editReview($row,$lists,$option); } ?> |
使用 require_once( JApplicationHelper::getPath( ‘admin_html‘ ) ) 来包含admin.reviews.html.php 文件。getPath() 函数带一个字符串参数并返回与组件文件一致的绝对路径。尽管我们没有指定组件名,但是它会自动包含适当的文件,即使是改变了组件名也一样。使用require_once() 确保文件只被包含一次。
addIncludePath() 成员函数会包含我们的数据表类, addIncludePath() 会自动包含所有我们定义在 tables 目录下的数据表类。
Joomla!设置 JPATH_COMPONENT 为后端代码的绝对路径。 DS 常量是指定的操作系统的目录分隔符。
editReview() 函数准备了一些 HMTL元素然后传给显示函数 HTML_reviews::editReview()。
第六步,创建 admin.reviews.html.php文件并加入以下代码:
<?php defined(‘_JEXEC‘)or die(‘Restricted access‘); class HTML_reviews{ function editReview($row,$lists,$option){ $editor = &JFactory::getEditor(); JHTML::_(‘behavior.calendar‘); ?> <form action="index.php" method="post" name="adminForm" id="adminForm"> <fieldsetclass="adminform"> <legend>Details</legend> <table> <tr> <td width="100" align="right" class="key">Name:</td> <td><inputclass="textarea" type="text" name="name" id="name" size="50" maxlength="250" value="<?php echo $row->name;?>"/></td> </tr> <tr> <td width="100" align="right" class="key">Address:</td> <td><inputclass="textarea" type="text" name="address" id="address" size="50" maxlength="250" value="<?php echo $row->address;?>"/></td> </tr> <tr> <td width="100" align="right" class="key">Reservations:</td> <td><?phpecho $lists[‘reservations‘];?></td> </tr> <tr> <td width="100" align="right" class="key">Quicktake:</td> <td><?phpecho $editor->display(‘quicktake‘,$row->quicktake,‘100%‘,‘150‘,‘40‘,‘5‘);?></td> </tr> <tr> <td width="100" align="right" class="key">Review:</td> <td><?phpecho $editor->display(‘review‘,$row->review,‘100%‘,‘250‘,‘40‘,‘10‘);?></td> </tr> <tr> <td width="100" align="right" class="key">Notes:</td> <td> <textareaclass="textarea" cols="20" rows="4" name="notes" style="width:500px"> <?phpecho $row->notes;?> </textarea> </td> </tr> <tr> <td width="100" align="right" class="key">Smoking:</td> <td><?phpecho $lists[‘smoking‘];?></td> </tr> <tr> <td width="100" align="right" class="key">Credit Cards:</td> <td><inputclass="textarea" type="text" name="credit_cards" id="credit_cards" size="50" maxlength="250" value="<?php echo $row->credit_cards;?>"/></td> </tr> <tr> <td width="100" align="right" class="key">Cuisine:</td> <td><inputclass="textarea" type="text" name="cuisine" id="cuisine" size="31" maxlength="31" value="<?php echo $row->cuisine;?>"/></td> </tr> <tr> <td width="100" align="right" class="key">Average Dinner Price:</td> <td><inputclass="textarea" type="text" name="avg_dinner_price" id="avg_dinner_price" size="5" maxlength="3" value="<?php echo $row->avg_dinner_price;?>"/></td> </tr> <tr> <td width="100" align="right" class="key">Review Date:</td> <td> <inputclass="textarea" type="text" name="review_date" id="review_date" size="25" maxlength="19" value="<?php echo $row->review_date;?>"/> <input type="reset" class="button" value="..." onclick="return showCalendar(‘review_date‘,‘y-mm-dd‘);"/> </td> </tr> <tr> <td width="100" align="right" class="key">Published:</td> <td><?phpecho $lists[‘published‘];?></td> </tr> </table> </fieldset> <input type="hidden" name="id" value="<?php echo $row->id;?>"/> <input type="hidden" name="option" value="<?php echo $option;?>"/> <input type="hidden" name="task" value=""/> </form> <?php } } ?> |
在浏览器地址栏输入 http://localhost/joomla/administrator/index.php?option=com_reviews&task=add,然后希望我会看到以下界面效果:
在上述代码中,JHTML::_(‘behavior.calendar‘);的JHTML::_() 做了什么?
Joomla!提供了很多自动生成HTML元素的函数,如下拉列表、复选框等。为了提供执行的效率,这些函数只有在需要的时候才会读到内存里。这个工作有 _() 函数来完成。
首先,JFactory::getEditor() 函数返回 HTML 编辑器,JHTML::_(‘behavior.calendar’) 函数会在 header 中加入JavaScript 和 CSS ,这是用在点评日期字段中弹出日历的代码:
class HTML_reviews
{
function editReview( $row, $lists, $option )
{
$editor =& JFactory::getEditor();
JHTML::_(‘behavior.calendar‘);
编辑器对象的成员函数 display() 返回选择的富文本编辑器的 HTML , 如果富文本编辑器不存在就返回<textarea> 元素。
display() 函数带有以下的参数:表单变量名、值、宽、高、列数和行数。当没有使用HTML 编辑器,最后两个参数是 <textarea> 的大小。代码片段如下:
<td>
<?php
echo $editor-->display( ‘quicktake‘, $row->quicktake , ‘100%‘, ‘150‘, ‘40‘, ‘5‘ ) ;
?>
</td>
第七步,管理员填完表单并且当即保存按钮后,我们需要保存信息到数据库里。开始,在admin.reviews.php中创建 saveReview() 函数,代码如下:
<?php defined(‘_JEXEC‘)or die(‘Restricted access‘); require_once(JApplicationHelper::getPath(‘admin_html‘)); JTable::addIncludePath(JPATH_COMPONENT.DS.‘tables‘); switch($task){ case ‘add‘: editReview($option); break; } function editReview($option){ $row = &JTable::getInstance(‘Review‘,‘Table‘); $lists =array(); $reservations =array( ‘0‘=>array(‘value‘=>‘None Taken‘,‘text‘=>‘None Taken‘), ‘1‘=>array(‘value‘=>‘Accepted‘,‘text‘=>‘Accepted‘), ‘2‘=>array(‘value‘=>‘Suggested‘,‘text‘=>‘Suggested‘), ‘3‘=>array(‘value‘=>‘Required‘,‘text‘=>‘Required‘) ); $lists[‘reservations‘] = JHTML::_(‘select.genericList‘,$reservations,‘reservations‘,‘class="inputbox"‘.‘‘,‘value‘,‘text‘,$row->reservations); $lists[‘smoking‘] = JHTML::_(‘select.booleanlist‘,‘somking‘,‘class="inputbox"‘,$row->smoking); $lists[‘published‘] = JHTML::_(‘select.booleanlist‘,‘published‘,‘class="inputbox"‘,$row->published); HTML_reviews::editReview($row,$lists,$option); } function saveReview($option){ global $mainframe; $row=&JTable::getInstance(‘review‘,‘Table‘); if(!$row->bind(JRequest::get(‘post‘))){ //使用 bind() 成员函数来加载表单中所有变量到 $row 中<br> echo "<script> alert(‘".$row->getError()."‘);window.history.go(-1);</script>\n"; exit(); } $row->quicktake = JRequest::getVar(‘quicktake‘,‘‘,‘post‘,‘string‘,JREQUEST_ALLOWRAW); $row->review = JRequest::getVar(‘review‘,‘‘,‘post‘,‘string‘,JREQUEST_ALLOWRAW); if(!$row->review_date){ $row->review_date =date(‘Y-m-d H:i:s‘); } if(!$row->store()){ echo "<script> alert(‘".$row->getError()."‘);window.history.go(-1);</script>\n"; exit(); } $mainframe->redirect(‘index.php?option=‘.$option,‘Review Saved‘); } ?> |
首先,将全局变量 $mainframe 传进来, $mainframe 对象提供很多成员函数来控制session 变量和 headers。然后将 TableReview 类的一个实例赋值给 $row ,类的名字由第一个参数和第二个参数组合而成,第二个参数是第一个参数的前缀。
然后,使用 bind() 成员函数来加载表单中所有变量到 $row 中。
bind() 函数传一个关联数组参数并且要数组的所有元素都要和对象的成员变量完全匹配。为了减少 SQL注入的风险,我们使用 Jrequest::get() 来清除 $_POST 的值,这个过程会过滤掉所有能够控制 SQL的字符。
如果 bind() 失败了会弹出一个 JavaScript 的警告对话框并返回到前一个页面。绑定后就可以直接操作 $row 的成员变量。
既然 quicktake 和 review 字段都接受 HTML内容,那么它们需要对 bind() 函数进行清除 HTML 的特殊处理。
要做这样处理,可以使用 Jrequest的成员函数getVar() 并传递表单的变量名、默认值、请求的数组、期望的格式和各自JREQUEST_ALLOWRAW 标识。以防点评没有选择日期,我们赋了当前日期给点评日期。
最后,调用 store() 函数,把所有的成员变量都转化成 UPDATE 和 INSERT 语句(由id 的值决定是 UPDATE 还是 INSERT)。因为是第一次创建记录,id 没有值,所以会构建INSERT 查询语句。
如果有 SQL错误就返回上一页, 通常这一类的 SQL错误都是由于 $row额外的成员变量而没有在数据表类中引起的。那么如果发现SQL 错误,第一时间就是要检查确保你的成员变量的拼写要与数据表的列一致。否则,如果 SQL 执行成功,将使用$mainframe 的 redirect() 函数返回组件的页面。
此时,我们还要在admin.review.php中的switch添加以下代码:
case ‘save‘:
saveReview($option);
break;
保存文件后访问这个地址:http://localhost/joomla/administrator/index.php?option=com_reviews&task=add你填好表单后点击保存,希望我能看到类似以下的页面:
如果没有异常,运行成功的话,刚才我添加的数据就应该在数据库表jos_reviews里面了。
现在尝试点击上述页面的“创建”按钮,你会有疑问,为什么我们不能点击“新建”按钮?
工具栏的按钮需要有名字为 adminForm 的表单才能有效,既然现在没有表单,那么点击任何的按钮都产生JavaScript 错误的。当你加上 adminForm 表单后,按钮马上就生效了。
第八步:既然我们的管理员不会有访问 phpMyAdmin 的权限,我们需要创建显示点评的列表。开始 我们在 admin.reviews.php中添加以下函数:
function showReviews($option){ $db =&JFactory::getDBO(); $query ="SELECT * FROM #__reviews"; $db->setQuery($query); $rows=$db->loadObjectList(); if($db->getErrorNum()){ echo $db->stderr(); return false; } HTML_reviews::showReviews($option,$rows); } |
这个函数加载了将被显示的数据,我们得到了一个当前数据库连接的引用, 然后调用它的成员函数 setQuery() ,setQuery() 函数带一个 SQL 语句的字符串为参数,但只做存储之后使用而不是立即执行。当调用 loadObjectList() 函数,之前设置的 SQL 语句就会执行并返回记录到一个数组中。如果运行过程出现错误,那么将显示错误和停止组件运行。
第九步,如果第八步一切正常,那么把记录结果的数组传给 admin.reviews.htlm.php 中的成员函数showReviews(),修改后代码如下:
<span style="color: #ff0000;">function showReviews($option,&$rows){ ?> <form action="index.php" method="post" name="adminForm"> <tableclass="adminlist"> <thead> <tr> <th width="20"> <input type="checkbox" name="toggle" value="" onclick="checkAll(<?php echo count($rows);?>)"/> </th> <thclass="title">Name</th> <th width="15%">Address</th> <th width="10%">Reservations</th> <th width="10%">Cuisine</th> <th width="10%">Credit Cards</th> <th width="5%" nowrap="nowrap">Published</th> </tr> </thead> <?php $k = 0; for($i=0,$n=count($rows);$i<$n;$i++){ $row=&$rows[$i]; $checked = JHTML::_(‘grid.id‘,$i,$row->id); $published = JHTML::_(‘grid.published‘,$row,$i); ?> <trclass="<?php echo "row$k";?>"> <td><?phpecho $checked;?></td> <td><?phpecho $row->name;?></td> <td><?phpecho $row->address;?></td> <td><?phpecho $row->reservations;?></td> <td><?phpecho $row->cuisine;?></td> <td><?phpecho $row->credit_cards;?></td> <td><?phpecho $published;?></td> </tr> <?php $k=1-$k; } ?> </table> <input type="hidden" name="option" value="<?php echo $option;?>"/> <input type="hidden" name="task" value=""/> <input type="hidden" name="boxchecked" value="0"/> </form> <?php }</span> |
这个函数定义了一个名为 adminForm(作为 JavaScript 应用) 并指向 index.php 的表单,接着显示一个带有 adminlist 类的表格,第一行为表格的头部,第一列是一个复选框“check all”,它会自动地选择页面上的所有记录。
接着使用传进来的记录数组来循环显示每一行的数组。要注意的是变量 $k,它在每次循环中会在 0 和 1 之中更换值,它的作用好是用来更换每个 <tr> 的类,从而控制了每行显示的背景色。
大部分的成员变量会直接输出,但是有两个比较特殊,JHTML::(‘grid.id‘) 函数将返回一个能被后端 JavaScript 识别的复选框,JHTML::_(‘grid.published‘) 函数返回一个基于成员变量 published 的值的图片,当 published 的值是 1 时,将返回打勾的图片,否则返回打“X”的图片。
在表格下面,有四个隐藏的变量,第一个处理 option 的值,以便路由到正确的组件,第二个是 task,它是在提交表单之前以便让工具栏中的 JavaScript 能给它赋值。第三个是boxchecked,当有任意一行的复选框被选择,boxchecked 被置为 1,当所有行的复选框被清除,boxchecked 被置为 0,它是用来辅助 JavaScript 来处理列表。
当完成了 HTML 代码的输出,最后一步就是更新文件 admin.reviews.php中的 switch() 语句,加入下面的高亮代码:
switch($task) { case ‘add‘: editReview($option ); break; case ‘save‘: saveReview($option ); break; <span style="color: #ff0000;">default: showReviews($option ); break;</span> } |
在浏览器中输入URL路径 http://localhost/joomla/administrator/index.php?
我们将扩展原有的代码来编辑记录, 而不是写一个新的功能。 在文件 admin.reviews.php中的 editReview() 函数中用以下的高亮代码来代替:$row=&JTable:getInstance(‘Review’, ‘Table’):
function editReview($option){ //$row = &JTable::getInstance(‘Review‘,‘Table‘); <span style="color: #ff0000;">$row =&JTable::getInstance(‘review‘,‘Table‘); $cid = JRequest::getVar(‘cid‘,array(0),‘‘,‘array‘); $id =$cid[0]; $row->load($id);</span> $lists =array(); $reservations =array( ‘0‘=>array(‘value‘=>‘None Taken‘,‘text‘=>‘None Taken‘), ‘1‘=>array(‘value‘=>‘Accepted‘,‘text‘=>‘Accepted‘), ‘2‘=>array(‘value‘=>‘Suggested‘,‘text‘=>‘Suggested‘), ‘3‘=>array(‘value‘=>‘Required‘,‘text‘=>‘Required‘) ); $lists[‘reservations‘] = JHTML::_(‘select.genericList‘,$reservations,‘reservations‘,‘class="inputbox"‘.‘‘,‘value‘,‘text‘,$row->reservations); $lists[‘smoking‘] = JHTML::_(‘select.booleanlist‘,‘somking‘,‘class="inputbox"‘,$row->smoking); $lists[‘published‘] = JHTML::_(‘select.booleanlist‘,‘published‘,‘class="inputbox"‘,$row->published); HTML_reviews::editReview($row,$lists,$option); } |
当执行 editReview() 函数时,我们取得 TableReview 对象来处理数据,然后会从表单中取得记录 ID 的数组变量 cid,既然在同一个时间只编辑一条记录,那我们只选择第一个数组元素来加载相应的记录。更新文件 admin.reviews.php 中的 switch() 语句如下:
switch($task){ <span style="color: #ff0000;">case ‘edit‘:</span> case ‘add‘: editReview($option); break; case ‘save‘: saveReview($option); break; default: showReviews($option); break; } |
你应该要提供 能够让用户通过点击来编辑各自的记录的链接 。 在文件admin.reviews.html.php 的 HTML_reviews::showReviews() 函数下加入一下高亮的代码:
function showReviews($option,&$rows){ ?> <form action="index.php" method="post" name="adminForm"> <tableclass="adminlist"> <thead> <tr> <th width="20"> <input type="checkbox" name="toggle" value="" onclick="checkAll(<?php echo count($rows);?>)"/> </th> <thclass="title">Name</th> <th width="15%">Address</th> <th width="10%">Reservations</th> <th width="10%">Cuisine</th> <th width="10%">Credit Cards</th> <th width="5%" nowrap="nowrap">Published</th> </tr> </thead> <?php <span style="color: #ff0000;">JLoader::import(‘joomla.filter.output‘);//貌似有点写错,感觉应该写成joomla.filter.filteroutput,不过这样运行没有错误</span> $k = 0; for($i=0,$n=count($rows);$i<$n;$i++){ $row=&$rows[$i]; $checked = JHTML::_(‘grid.id‘,$i,$row->id); $published = JHTML::_(‘grid.published‘,$row,$i); <span style="color: #ff0000;">$link = JFilterOutput::ampReplace(‘index.php?option=‘.$option.‘&task=edit&cid[]=‘.$row->id);</span> ?> <trclass="<?php echo "row$k";?>"> <td><?phpecho $checked;?></td> <span style="color: #ff0000;"> <td> <a href="<?php echo $link;?>"> <?phpecho $row->name;?> </a> </td></span> <td><?phpecho $row->address;?></td> <td><?phpecho $row->reservations;?></td> <td><?phpecho $row->cuisine;?></td> <td><?phpecho $row->credit_cards;?></td> <td><?phpecho $published;?></td> </tr> <?php $k=1-$k; } ?> </table> <input type="hidden" name="option" value="<?php echo $option;?>"/> <input type="hidden" name="task" value=""/> <input type="hidden" name="boxchecked" value="0"/> </form> <?php } |
为了兼容 XHTML, 我们需要确保符号 & 使用 & 来代替, 我们使用 ampReplace()来处理 , 它是 JFilterOutput 类的成员函数 , JFilterOutput 通过调用JLoader::import(‘joomla.filter.output‘); 来加载。 Joomla! 提供了许多不同的库, 例如 XML处理和 RSS输出等。我们使用 JLoader::import 函数来按需要加载代码,而不是每次加载Joomla! 时都加载所用的库。
你可能已经注意到了在编辑页面的工具栏上有个 “应用” 按钮, 它允许人们保存内容的同时,页面依然保留在编辑的状态,为了是应用按钮生效,需要在文件 admin.reviews.php 中做两个改变,在 switch() 语句中加入一下的高亮代码
switch($task){ case ‘edit‘: case ‘add‘: editReview($option); break; <span style="color: #ff0000;">case ‘apply‘: case ‘save‘: saveReview($option,$task); break;</span> default: showReviews($option); break; } |
在 saveReview() 函数中加入 $task 参数:function saveReview( $option, $task ) 将 saveReview() 函数的最后一行更改为如下:
function saveReview($option,$task){ global $mainframe; $row=&JTable::getInstance(‘review‘,‘Table‘); if(!$row->bind(JRequest::get(‘post‘))){ echo "<script> alert(‘".$row->getError()."‘);window.history.go(-1);</script>\n"; exit(); } $row->quicktake = JRequest::getVar(‘quicktake‘,‘‘,‘post‘,‘string‘,JREQUEST_ALLOWRAW); $row->review = JRequest::getVar(‘review‘,‘‘,‘post‘,‘string‘,JREQUEST_ALLOWRAW); if(!$row->review_date){ $row->review_date =date(‘Y-m-d H:i:s‘); } if(!$row->store()){ echo "<script> alert(‘".$row->getError()."‘);window.history.go(-1);</script>\n"; exit(); } <span style="color: #ff0000;">switch ($task){ case ‘apply‘: $msg =‘Changes to Review saved‘; $link =‘index.php?option=‘.$option.‘&task=edit&cid[]=‘.$row->id; break; default: $msg =‘asdfsdfReview Saved‘; $link =‘index.php?option=‘.$option; break; } $mainframe->redirect($link,$msg);</span> } |
增加删除的功能是相当的简单,在文件 admin.reviews.php 的 switch() 语句中加入以下的case 语句:
switch($task){ case ‘edit‘: case ‘add‘: editReview($option); break; case ‘apply‘: case ‘save‘: saveReview($option,$task); break; <span style="color: #ff0000;">case ‘remove‘: removeReviews($option); break;</span> default: showReviews($option); break; } |
当然也要增加 removeReviews() 函数:
function removeReviews($option){ global $mainframe; $cid = JRequest::getVar(‘cid‘,array(),‘‘,‘array‘); $db =&JFactory::getDBO(); if(count($cid)){ $cids = implode(‘,‘,$cid); $query ="DELETE FROM #__reviews WHERE id IN ($cids)"; $db->setQuery($query); if(!$db->query()){ echo "<script> alert(‘".$db->getErrorMsg()."‘);window.history.go(-1);</script>"; } } $mainframe->redirect(‘index.php?option=‘.$option); } |
好了,基本做到这里,组件的后台管理小例子已经完成了
接下来,我要做做这个组件的前台显示
第一步,在网站根目录/component/创建com_reviews文件夹,在里面创建一个reviews.php的文件,代码如下:
<?php defined(‘_JEXEC‘)or die(‘Restricted access‘); jimport(‘joomla.application.helper‘); require_once(JApplicationHelper::getPath(‘html‘)); JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.‘components‘.DS.$option.DS.‘tables‘); switch($task){ default: showPublishedReviews($option); break; } function showPublishedReviews($option){ $db = &JFactory::getDBO(); $query ="SELECT * FROM #__reviews WHERE published = ‘1‘ ORDER BY review_date DESC"; $db->setQuery($query); $rows=$db->loadObjectList(); if($db->getErrorNum()){ echo $db->stderr(); return false; } HTML_reviews::showReviews($rows,$option); } ?> |
与后端的方法相似,require_once( JApplicationHelper::getPath( ‘html‘ ) ); 导进文件reviews.html.php,传递 JPATH_ADMINISTRATOR.DS.‘components‘.DS.$option.DS.‘tables‘ 到Jtable::addIncludePath(); 导进数据表类。 最后 switch() 语句设置了默认的 case 来显示所有发布的点评。这里的 SQL 语句确保只有发布的点评被选择并且以点评日期的倒序来排序。
第二步,在刷新页面之前 , 我们需要 在 /component/com_reviews/reviews.html.php 中加入HTML_reviews 类:
<?php class HTML_reviews{ function showReviews($rows,$option){ ?> <table> <?php foreach($rows as $row){ $link =‘index.php?option=‘.$option.‘&id=‘.$row->id.‘&task=view‘; echo ‘<tr><td><a href="‘.$link.‘">‘.$row->name.‘</a></td></tr>‘; } ?> </table> <?php } } ?> |
如果你没有写任何的代码来处理 “view” “task”,当你单击一条链接后,你看到的是相同的页面,在 reviews.php 中加入以下代码:
function viewReview($option){ $id = JRequest::getVar(‘id‘,0); $row = & JTable::getInstance(‘review‘,‘Table‘); $row->load($id); if(!$row->published){ JError::raiseError(404,JText::_(‘Invalid ID provided‘)); } HTML_reviews::showReview($row,$option); } |
先,用 getVar() 获取请求的 id,它能检查变量的各种攻击。外部的数据处理要很小心,特别是处理公共访问的网站的数据,在我们的代码中统一使用 getVar() 将会提供一个合理的安全层。如果 id 的值丢失或者不合法,第二个参数 0 将会作为默认值提供给 id。然后,我们从后端得到一个数据表类,加载相应 id 的记录后,我们检查选择的记录是否被发布,如果不是发布的,我们用 JError 的成员函数 raiseError() 来输出找不到信息的404 页面
这个检查确保不让用户随便输入 id 来获取点评,而且如果记录不存在也会显示以上的页面。viewReview() 函数会做所有的事情来加载请求的点评,但是我们仍然需要加入代码来
调用这个函数,加入下面的高亮代码到 switch() 中:
switch($task){ <span style="color: #ff0000;">case ‘view‘: viewReview($option); break;</span> default: showPublishedReviews($option); break; } |
我们也需要在我们的输出类创建一个显示函数,在 reviews.html.php 文件中加入showReview() 函数到 HTML_reviews:
<?php class HTML_reviews{ function showReviews($rows,$option){ ?> <table> <?php foreach($rows as $row){ $link =‘index.php?option=‘.$option.‘&id=‘.$row->id.‘&task=view‘; echo ‘<tr><td><a href="‘.$link.‘">‘.$row->name.‘</a></td></tr>‘; } ?> </table> <?php } <span style="color: #ff0000;">function showReview($row,$option){ ?> <pclass="contentheading"><?phpecho $row->name;?></p> <pclass="createdate"><?phpecho JHTML::date($row->review_date);?></p> <p><?phpecho $row->quicktake;?></p> <p><strong>Address:</strong><?phpecho $row->address;?></p> <p><strong>Cuisine:</strong><?phpecho $row->cuisine;?></p> <p><strong>Average dinner price:</strong><?phpecho $row->avg_dinner_price;?></p> <p><strong>Credit cards:</strong><?phpecho $row->credit_cards;?></p> <p><strong>Reservations:</strong><?phpecho $row->reservations;?></p> <p> <strong>Smoking:</strong> <?php if($row->smoking==0){ echo "No"; } else{ echo "Yes"; } ?> </p> <p><?phpecho $row->review;?></p> <p><em>Notes:</em><?phpecho $row->notes;?></p> <?php$link =‘index.php?option=‘.$option;?> <a href="<?php echo $link;?>"><return to the reviews</a> <?php }</span> } ?> |
showReview() 函数传进一个数据库行对象和组件的名字作为参数,这行记录的大部分字段都以 HTML 格式显示,也包含许多逻辑。Smoking 字段陪赋给合适的 Yes 或者 No 值。调用 JHTML::Date() 来格式化从数据库取出来的时间戳。最后,显示一个可以返回点评列表的链接,保存文件后,再次点击点评的链接。
好了,现在终于前台的文章可以查看了。真是太爽了。
过了一天,我继续开发“评论”代码块,做做以下记录。
第一步,创建一个评论表,代码如下:
CREATE TABLE `jos_reviews_comments`( `id`int(11)NOT NULL auto_increment, `review_id`int(11)NOT NULL, `user_id`int(11)NOT NULL, `full_name`varchar(50)NOT NULL, `comment_date` datetimeNOT NULL, `comment_text` textNOT NULL, PRIMARY KEY (`id`) ) |
第二步,既然有了新的数据库表格,那么我们就要添加一个新的数据库表类了。下面我来做做,在administrator/component/com_reviews文件夹下的tables文件创建comment.php文件,代码如下:
<?php defined(‘_JEXEC‘)or die(‘Restricted access‘); class TableCommentextends JTable{ var $id = null; var $review_id = null; var $user_id = null; var $full_name = null; var $comment_date = null; var $comment_text = null; function __construct(&$db){ parent::__construct(‘#__reviews_comments‘,‘id‘,$db); } } ?> |
第三步,现在我希望得到页面效果是评论在点评详情的下面显示,好了,目标明确,现在我来开发一下,去到根目录/component/com_reviews文件夹,对reviews.html.php进行编辑,添加以下代码高亮部分:
function showCommentForm($option,$review_id,$name){ ?> <br /><br /> <form action="index.php" method="post"> <table> <tr> <td><strong>Name:</strong></td> <td><inputclass="textarea" type="text" name="full_name" id="full_name" value="<?php echo $name;?>"/></td> </tr> <tr> <td><strong>Comment:</strong></td> <td><textareaclass="textarea" cols="20" rows="4" name="comment_text" id="comment_text" style="width:500px;"></textarea></td> </tr> </table> <input type="hidden" name="review_id" value="<?php echo $review_id;?>"/> <input type="hidden" name="task" value="comment"/> <input type="hidden" name="option" value="<?php echo $option;?>"/> <input type="submit" class="button" id="button" value="Submit"/> </form> <?php } |
第四步,既然reviews.html.php有了showCommentForm方法,那么我们就应该找个文件写些代码去调用它,所以我就找到根目录/component/com_reviews/reviews.php这个文件,知道了改哪个文件之后,我就要想想改文件的哪个部分,现在我要修改viewReview方法这个部分,修改后代码如下:
function viewReview($option){ $id = JRequest::getVar(‘id‘,0); $row = & JTable::getInstance(‘review‘,‘Table‘); $row->load($id); if(!$row->published){ JError::raiseError(404,JText::_(‘Invalid ID provided‘)); } HTML_reviews::showReview($row,$option); $user =&JFactory::getUser(); if($user->name){ $name =$user->name; } else{ $name =‘‘; } HTML_reviews::showCommentForm($option,$id,$name); } |
现在登陆一下:http://localhost/Joomla/index.php,应该可以看到以下类似页面:
one,当我们填写和提交表单之前,我们需要加入处理输入数据和插入到数据库。那么,我们就改改reviews.php这个文件,先加入插入评论的方法addComment代码如下:
function addComment($option){ global $mainframe; $row =&JTable::getInstance(‘comment‘,‘Table‘); if(!$row->bind(JRequest::get(‘post‘))){ echo "<script> alert(‘".$row->getError()."‘);window.history.go(-1);</script>\n"; exit(); } $row->comment_date =date(‘Y-m-d H:i:s‘); $user =&JFactory::getUser(); if($user->id){ $row->user_id =$user->id; } if(!$row->store()){ echo "<script> alert(‘".$row->getError()."‘);window.history.go(-1);</script>\n"; exit(); } $mainframe->redirect(‘index.php?option‘.$option.‘&id=‘.$row->review_id.‘&task=view‘,‘Comment Added.‘); } |
有了插入数据的方法,那么我要找个地方去调用它,就在reviews.php中的switch块进行控制,现在去改改代码:
switch($task){ case ‘view‘: viewReview($option); break; case ‘comment‘: addComment($option); break; default: showPublishedReviews($option); break; } |
第六步,估计这个时候,我可以添加评论数据了。尝试了一下,去数据库表看了一下数据,果然添加成功了。现在我要在前台显示评论的内容,我希望评论跟在文章内容下面,那么,我想好了前台显示的大概效果,现在就来修改一下reviews.html.php的内容了,追加代码如下:
function showComment($row){ ?> <br /><br /> <p> <strong><?phpecho $row->full_name;?></strong> <em><?phpecho JHTML::date($row->comment_date);?></em> </p> <p> <?phpecho $row->comment_text;?> </p> <?php } |
第七步,搞定了前台的显示,那么下一步,就去reviews.php中修改一下viewReview这个方法,代码如下:
function viewReview($option){ $id = JRequest::getVar(‘id‘,0); $row = & JTable::getInstance(‘review‘,‘Table‘); $row->load($id); if(!$row->published){ JError::raiseError(404,JText::_(‘Invalid ID provided‘)); } HTML_reviews::showReview($row,$option); $db = &JFactory::getDBO(); $db->setQuery("SELECT * FROM #__reviews_comments WHERE review_id = ‘$id‘"); $rows =$db->loadObjectList(); foreach($rows as $row){ HTML_reviews::showComment($row); } $user =&JFactory::getUser(); if($user->name){ $name =$user->name; } else{ $name =‘‘; } HTML_reviews::showCommentForm($option,$id,$name); } |
大功告成;显示效果
joomla代码编译到这里