创建Joomla组件之THE ADMIN INTERFACE
创建管理员界面
序言
前三个例子我们开发了一个从数据库中获取数据的MVC组件。可是除了手工添加数据或者使用其他工具外,我们没有办法添加数据。本教程中,我们将开发一个管理部分从而能够管理数据。
创建基本框架
后 台管理基本框架与前台站点部分基本相同。管理部分的主入口是 admin.hello.php. 这个文件与我们在前他部分使用的hello.php是一样的,除了controller改为 HellosController.默认的controller也是controller.php,并且除了controller名字是 HellosController以外,其他与前台部分的controller.php都一样,还有不同就是将默认调用hellos view,这个view显示greetings的列表
以下admin.hello.php代码清单:
<?php
/**
* @package Joomla.Tutorials
* @subpackage Components
* @link http://dev.joomla.org/component/option,com_jd-wiki/Itemid,31/id,tutorials:components/
* @license GNU/GPL
*/
// no direct access
defined( ‘_JEXEC’ ) or die( ‘Restricted access’ );
// Require the base controller
require_once( JPATH_COMPONENT.DS.’controller.php’ );
// Require specific controller if requested
if($controller = JRequest::getWord(‘controller’)) {
$path = JPATH_COMPONENT.DS.’controllers’.DS.$controller.’.php’;
if (file_exists($path)) {
require_once $path;
} else {
$controller = ”;
}
}
// Create the controller
$classname = ‘HellosController’.$controller;
$controller = new $classname( );
// Perform the Request task
$controller->execute( JRequest::getVar( ‘task’ ) );
// Redirect if set by the controller
$controller->redirect();
?>
view和model都是以hellos开头的,下面将介绍model和view.
创建管理员界面Hellos Model
Hellos Model
Hellos Model非常简单,我们需要的是从数据库返回hellos列表,这通过getData()方法实现。
还有一个_getList()的保护方法,这个方法用来简化从数据库返回数据的任务,我们只是简单的传递query并且返回记录列表。
也许以后某个时候,我们在另一个方法中使用这个查询,因而我们创建了一个私有方法 _buildQuery() ,这个方法返回query,并且传递给_getList(). 这样可以集中在一处来修改查询语句。
getData() 和 _buildQuery() 方法是必须需要的:
_buildQuery() 仅仅是返回语句,代码如下:
/**
* Returns the query
* @return string The query to be used to retrieve the rows from the database
*/
function _buildQuery()
{
$query = ‘ SELECT * ‘
. ‘ FROM #__hello ‘
;
return $query;
}
getData() 将用这个sql从数据库返回数据. 也许我们需要两次获取同样数据,重复运行查询是非常浪费的,因而,我们保存结果在一个保护属性_data中,这样只需查询一次就可以了。
以下是 getData() 方法:
/**
* Retrieves the hello data
* @return array Array of objects containing the data from the database
*/
function getData()
{
// Lets load the data if it doesn’t already exist
if (empty( $this->_data ))
{
$query = $this->_buildQuery();
$this->_data = $this->_getList( $query );
}
return $this->_data;
}
完整model代码如下(models/hellos.php):
<?php
/**
* Hellos Model for Hello World Component
*
* @package Joomla.Tutorials
* @subpackage Components
* @link http://dev.joomla.org/component/option,com_jd-wiki/Itemid,31/id,tutorials:components/
* @license GNU/GPL
*/
// Check to ensure this file is included in Joomla!
defined(‘_JEXEC’) or die();
jimport( ‘joomla.application.component.model’ );
/**
* Hello Model
*
* @package Joomla.Tutorials
* @subpackage Components
*/
class HellosModelHellos extends JModel
{
/**
* Hellos data array
*
* @var array
*/
var $_data;
/**
* Returns the query
* @return string The query to be used to retrieve the rows from the database
*/
function _buildQuery()
{
$query = ‘ SELECT * ‘
. ‘ FROM #__hello ‘
;
return $query;
}
/**
* Retrieves the hello data
* @return array Array of objects containing the data from the database
*/
function getData()
{
// Lets load the data if it doesn’t already exist
if (empty( $this->_data ))
{
$query = $this->_buildQuery();
$this->_data = $this->_getList( $query );
}
return $this->_data;
}
}
创建管理员界面Hellos view
Hellos View
现在model已经返回了数据,那么就需要view来显示数据。view与前台的view也相似
与前台一样,这里的model也是自动初始化的。view主要有三行程序,一是得到model返回的数据,二是传递数据给模板,三是调用display方法,显示输出。
以下是 views/hellos/view.html.php. 代码清单:
<?php
/**
* Hellos View for Hello World Component
*
* @package Joomla.Tutorials
* @subpackage Components
* @link http://dev.joomla.org/component/option,com_jd-wiki/Itemid,31/id,tutorials:components/
* @license GNU/GPL
*/
// Check to ensure this file is included in Joomla!
defined(‘_JEXEC’) or die();
jimport( ‘joomla.application.component.view’ );
/**
* Hellos View
*
* @package Joomla.Tutorials
* @subpackage Components
*/
class HellosViewHellos extends JView
{
/**
* Hellos view display method
* @return void
**/
function display($tpl = null)
{
JToolBarHelper::title( JText::_( ‘Hello Manager’ ), ‘generic.png’ );
JToolBarHelper::deleteList();
JToolBarHelper::editListX();
JToolBarHelper::addNewX();
// Get data from the model
$items =& $this->get( ‘Data’);
$this->assignRef( ‘items’, $items );
parent::display($tpl);
}
}
创建管理员界面Hellos Template
Hellos Template
模板获取view传递的数据,并生成输出。我们用一个表格显示输出,尽管前台的模板非常简单,可是后台的管理复杂一些从而能处理数据。
这是 views/hellos/tmpl/default.php的代码清单 :
<?php defined(‘_JEXEC’) or die(‘Restricted access’); ?>
<form action=”index.php” method=”post” name=”adminForm”>
<div id=”editcell”>
<table class=”adminlist”>
<thead>
<tr>
<th width=”5″>
<?php echo JText::_( ‘ID’ ); ?>
</th>
<th>
<?php echo JText::_( ‘Greeting’ ); ?>
</th>
</tr>
</thead>
<?php
$k = 0;
for ($i=0, $n=count( $this->items ); $i < $n; $i++)
{
$row =& $this->items[$i];
?>
<tr class=”<?php echo “row$k”; ?>”>
<td>
<?php echo $row->id; ?>
</td>
<td>
<?php echo $row->greeting; ?>
</td>
</tr>
<?php
$k = 1 – $k;
}
?>
</table>
</div>
<input type=”hidden” name=”option” value=”com_hello” />
<input type=”hidden” name=”task” value=”” />
<input type=”hidden” name=”boxchecked” value=”0″ />
<input type=”hidden” name=”controller” value=”hello” />
</form>
你看到我们的输出用一个form包含,现在并不是必须的,但是以后有用处。
以下是新增的5个文件,你可以把这些文件添加到xml中,并试试。
admin.hello.php
controller.php
models/hellos.php
views/hellos/view.html.php
views/hellos/tmpl/default.php
创建管理员界面 增加管理功能
直到目前为止,管理界面没有什么实际用户,除了显示数据。我们需要增加一些按钮和链接,从而能执行管理功能。
The Toolbar
toolbar是Joomla组件管理控制面板的顶部。这个组件同样也需要一个,在Joomla中这是非常简单的。现在来增加按钮来处理添加,修改,删除记录,还需要增加一个toolbar上的标题。
以下的代码就可以添加按钮了,为添加按钮,我们使用了Joomla的 JToolBarHelper 静态类。
JToolBarHelper::title( JText::_( ‘Hello Manager’ ), ‘generic.png’ );
JToolBarHelper::deleteList();
JToolBarHelper::editListX();
JToolBarHelper::addNewX();
以上的三个方法创建了三个按钮,deleteList()有三个可选参数,一是提示用户确认删除的字符串,二是请求中需要发送的task,默认是remove,三是显示在删除按钮下边的文字。
editListX()和addNewX()方法有两个参数,一是task(默认的是edit和add),二是按钮下显示的文字。
请 注意JText::_ 方法,这是一个处理多语言的方便的函数,这个寻找你语言文件中对应的字符串,并返回转换后的字符串,如果没有找到字符串,将直接返回传递给 JText::_的字符串。如果你要翻译你的组件,你要做的工作就是创建一个语言文件,这个语言文件包含字符串的map集合。
复选框和链接
按钮现在有了,可是修改和删除是要针对已存在的记录。但是需要用户选择那些记录需要进行这些操作。因此,我们在模板中添加了复选框。我们在表格中添加额外的一列。在这一个列的表头中,我们添加了一个复选框,这个复选框用来选中和清除所有复选框的装提案。
<th width=”20″>
<input type=”checkbox” name=”toggle” value=”” onclick=”checkAll(<?php echo count( $this->items ); ?>);” />
</th>
Joomla的Javascript包含了一个函数checkAll,这里我们使用了这个函数。
接下来需要给每一行添加一个复选框,Joomla的JHTML类有一个函数JHTML::_(),以下就是代码:
$checked = JHTML::_( ‘grid.id’, $i, $row->id );
$row =& $this->items[$i];
<td>
<?php echo $checked; ?>
</td>
需要需要修改记录的时候,先选中复选框,然后再点击上边的edit按钮,这样的操作比较繁琐,因此,我们要添加一个链接,直接进入编辑界面。
以下是代码:
$link = JRoute::_( ‘index.php?option=com_hello>controller=hello>task=edit>cid[]=’. $row->id );
<td>
<a href=”/<?php echo $link; ?>”><?php echo $row->greeting; ?></a>
</td>
值得注意的是,链接中的controller指向hello controller,这个controller处理数据操作。
在 返回看以下form,其中有四个隐藏的输入域。第一个是option,这是是进入component必须的,第二是task,对应这toolbar上的按 钮操作,如果没有这个字段,javascript将报错,从而操作失败。第三个字段是boxchecked,主要是有多少复选框被选中,edit和 delete按钮操作会检查这个字段不小于0,最后一个是controller,这个输入决定采用那个controller.
以下是模板 default.php 的代码清单:
<?php defined(‘_JEXEC’) or die(‘Restricted access’); ?>
<form action=”index.php” method=”post” name=”adminForm”>
<div id=”editcell”>
<table class=”adminlist”>
<thead>
<tr>
<th width=”5″>
<?php echo JText::_( ‘ID’ ); ?>
</th>
<th>
<?php echo JText::_( ‘Greeting’ ); ?>
</th>
</tr>
</thead>
<?php
$k = 0;
for ($i=0, $n=count( $this->items ); $i < $n; $i++)
{
$row =& $this->items[$i];
?>
<tr class=”<?php echo “row$k”; ?>”>
<td>
<?php echo $row->id; ?>
</td>
<td>
<?php echo $row->greeting; ?>
</td>
</tr>
<?php
$k = 1 – $k;
}
?>
</table>
</div>
<input type=”hidden” name=”option” value=”com_hello” />
<input type=”hidden” name=”task” value=”” />
<input type=”hidden” name=”boxchecked” value=”0″ />
<input type=”hidden” name=”controller” value=”hello” />
</form>
现在hellos view完成了,去试试吧。
创建管理员界面 增加编辑功能 上
现在hellos view完成了,现在需要完成hello view和 model, 他们实际复杂数据处理工作。
Hello Controller
默认的controller仅仅是展示数据,现在需要controller能处理从hellos view发出的添加,删除,修改任务,
添加和编辑本质是相同的任务,他们都是显示给用户一个form来做greeting编辑,不同的是添加是一个空的form,而edit有数据,因此我们把add任务映射给edit钩子函数。下面的构造器中做了这个操作
/**
* constructor (registers additional tasks to methods)
* @return void
*/
function __construct()
{
parent::__construct();
// Register Extra tasks
$this->registerTask( ‘add’ , ‘edit’ );
}
JController::registerTask是将add映射到edit钩子函数上。
现在我们处理编辑任务,controller处理edit任务相当简单,所要做的仅仅设指定view和模板,这里在编辑的同事要禁用主菜单,从而用户不能离开而不保存数据。
edit 任务的钩子函数清单:
/**
* display the edit form
* @return void
*/
function edit()
{
JRequest::setVar( ‘view’, ‘hello’ );
JRequest::setVar( ‘layout’, ‘form’ );
JRequest::setVar(‘hidemainmenu’, 1);
parent::display();
}
Hello View
Hello view 显示一个表单允许用户编辑. display要完成下面一些简单任务:
从model获取数据
创建toolbar
给模板template传递数据
调用display()填充模板
因为要处理编辑和添加,所以稍稍有点复杂。在toolbar中需要用户知道是否在添加或编辑,从而我们决定触发那个任务。
因为我们已经从model获取了数据,因而可以推断是那个任务被触发,如果是编辑,那么id字段是有数据的,否则,这个字段就是空的,由此可以确定是添加还是编辑记录。
在toolbar中还添加了两个按钮,保存和取消。
We will add two buttons to the toolbar: save and cancel. Though the functionality will be the same, we want to display different buttons depending on whether it is a new or existing record. If it is a new record, we will display cancel. If it already exists, we will display close.
display 方法的清单如下:
/**
* display method of Hello view
* @return void
**/
function display($tpl = null)
{
//get the hello
$hello =& $this->get(‘Data’);
$isNew = ($hello->id < 1);
$text = $isNew ? JText::_( ‘New’ ) : JText::_( ‘Edit’ );
JToolBarHelper::title( JText::_( ‘Hello’ ).’: <small><small>[ ‘ . $text.’ ]</small></small>’ );
JToolBarHelper::save();
if ($isNew) {
JToolBarHelper::cancel();
} else {
// for existing items the button is renamed `close`
JToolBarHelper::cancel( ‘cancel’, ‘Close’ );
}
$this->assignRef(‘hello’, $hello);
parent::display($tpl);
}
创建管理员界面 增加编辑功能 下
现在我们来创建model.
model有两个属性 _id and _data. _id存贮id,_data存储greeting数据.
构造器中首先从request中取得id
/**
* Constructor that retrieves the ID from the request
*
* @access public
* @return void
*/
function __construct()
{
parent::__construct();
$array = JRequest::getVar(‘cid’, 0, ”, ‘array’);
$this->setId((int)$array[0]);
}
JRequest::getVar() 方法用来从request中获取数据。第一个参数是form变量的名称,第二个参数是参数默认值,第三个参数he name of the hash to retrieve the value from,第四个是数据类型。
构造器将取得cid数组中的第一个值并赋给id.
setId()被用来设置id,如果id变化了,那么对应的data也应该变化,否则就出错了,因此当我们设置id的值的时候,清空data的数据。
/**
* Method to set the hello identifier
*
* @access public
* @param int Hello identifier
* @return void
*/
function setId($id)
{
// Set id and wipe data
$this->_id = $id;
$this->_data = null;
}
最后还要有getData()来获取数据,getData检查 data是否已经设置,如果已经设置,仅仅返回,如果没有,就从数据库载入。
/**
* Method to get a hello
* @return object with data
*/
function &getData()
{
// Load the data
if (empty( $this->_data )) {
$query = ‘ SELECT * FROM #__hello ‘.
‘ WHERE id = ‘.$this->_id;
$this->_db->setQuery( $query );
$this->_data = $this->_db->loadObject();
}
if (!$this->_data) {
$this->_data = new stdClass();
$this->_data->id = 0;
$this->_data->greeting = null;
}
return $this->_data;
}
表单 Form
以下是表单的代码清单:
<?php defined(‘_JEXEC’) or die(‘Restricted access’); ?>
<form action=”index.php” method=”post” name=”adminForm” id=”adminForm”>
<div class=”col100″>
<fieldset class=”adminform”>
<legend><?php echo JText::_( ‘Details’ ); ?></legend>
<table class=”admintable”>
<tr>
<td width=”100″ align=”right” class=”key”>
<label for=”greeting”>
<?php echo JText::_( ‘Greeting’ ); ?>:
</label>
</td>
<td>
<input class=”text_area” type=”text” name=”greeting” id=”greeting” size=”32″ maxlength=”250″ value=”<?php echo $this->hello->greeting;?>” />
</td>
</tr>
</table>
</fieldset>
</div>
<div class=”clr”></div>
<input type=”hidden” name=”option” value=”com_hello” />
<input type=”hidden” name=”id” value=”<?php echo $this->hello->id; ?>” />
<input type=”hidden” name=”task” value=”” />
<input type=”hidden” name=”controller” value=”hello” />
</form>
注意,有一个id隐藏项,我们不应该改变id,而仅仅是传递。
创建管理员界面 保存记录功能上
到目前为止,我们仅处理了编辑和添加,还有保存,删除,取消没处理,现在要写执行这些任务的代码。
保存记录
理论上我们需要实现保存数据的功能,可能需要一些逻辑分支处理不同情况。幸运的是joomla接管了很多这样的工作。
JTable类实现了数据操作功能,而不必关心实际的sql语句,并且把数据从form加入数据库更简单了。
创建 Table 类
JTable是一个抽象类,对于指定的数据库表我们要从JTable继承类,这里我们只需要创建一个类,添加字段作为shuxing ,重写constructor指定表名和主键就可以了
以下是JTable的代码清单:
<?php
/**
* Hello World table class
*
* @package Joomla.Tutorials
* @subpackage Components
* @link http://dev.joomla.org/component/option,com_jd-wiki/Itemid,31/id,tutorials:components/
* @license GNU/GPL
*/
// no direct access
defined(‘_JEXEC’) or die(‘Restricted access’);
/**
* Hello Table class
*
* @package Joomla.Tutorials
* @subpackage Components
*/
class TableHello extends JTable
{
/**
* Primary Key
*
* @var int
*/
var $id = null;
/**
* @var string
*/
var $greeting = null;
/**
* Constructor
*
* @param object Database connector object
*/
function TableHello( &$db ) {
parent::__construct(‘#__hello’, ‘id’, $db);
}
}
?>
这里定义了id 和greeting,构造器中指定了表名hello和主键id
创建管理员界面 保存记录功能下
在model中实现数据操作
现在添加一个store方法用来保存数据,store要绑定form传递的数据到TableHello对象,检查数据格式是否正确,保存数据。
store方法代码如下:
/**
* Method to store a record
*
* @access public
* @return boolean True on success
*/
function store()
{
$row =& $this->getTable();
$data = JRequest::get( ‘post’ );
// Bind the form fields to the hello table
if (!$row->bind($data)) {
$this->setError($this->_db->getErrorMsg());
return false;
}
// Make sure the hello record is valid
if (!$row->check()) {
$this->setError($this->_db->getErrorMsg());
return false;
}
// Store the web link table to the database
if (!$row->store()) {
$this->setError($this->_db->getErrorMsg());
return false;
}
return true;
}
第 一行获取了JTable类实例,如果正确命名了名字,我们不必指定名字,Jmodel类自动找到合适的Jtable,我们创建了一个tables目录,并 将JTable 命名为TableHello保存在 hello.php文件中,遵循这样的约定,就可以自动创建对象。
第二行我们返回form的数据。JRequest做的非常简单,本例中,我们获取了所有post的变量,这些变量是以数组方式返回的。
其余的非常简单了- bind, check and store. bind() 拷贝form的相应变量到JTable中. 本例中id和greeting赋值到TableHello对象中.
check() 执行数据验证. 在JTable() class, 这个方法仅仅是简单返回true. 尽管现在没有实际用处,但是以后check可以做验证。
store()方法保存数据到数据库中,如果id为0,将创建一个新目录,否则更新记录。
添加controller任务
现在来添加任务,任务的名称是save
以下是代码清单:
/**
* save a record (and redirect to main page)
* @return void
*/
function save()
{
$model = $this->getModel(‘hello’);
if ($model->store()) {
$msg = JText::_( ‘Greeting Saved!’ );
} else {
$msg = JText::_( ‘Error Saving Greeting’ );
}
// Check the table in so it can be edited…. we are done with it anyway
$link = ‘index.php?option=com_hello’;
$this->setRedirect($link, $msg);
}
我们所要做的是取得model,调用store方法,然后用 setRedirect(),返回greetings的列表页面,同事返回一个信息,显示在页面的顶部。
创建管理员界面 删除记录
删除记录
在model中实现功能
model中获取返回的IDS,并调用mdoel删除记录,以下是代码清单:
/**
* Method to delete record(s)
*
* @access public
* @return boolean True on success
*/
function delete()
{
$cids = JRequest::getVar( ‘cid’, array(0), ‘post’, ‘array’ );
$row =& $this->getTable();
foreach($cids as $cid) {
if (!$row->delete( $cid )) {
$this->setError( $row->getErrorMsg() );
return false;
}
}
return true;
}
JRequest::getVar()返回cid数据, 然后调用$row->delete()删除每一行.
在controller中处理设置删除任务处理,与save是相似的。
/**
* remove record(s)
* @return void
*/
function remove()
{
$model = $this->getModel(‘hello’);
if(!$model->delete()) {
$msg = JText::_( ‘Error: One or More Greetings Could not be Deleted’ );
} else {
$msg = JText::_( ‘Greeting(s) Deleted’ );
}
$this->setRedirect( ‘index.php?option=com_hello’, $msg );
}
取消操作:
/**
* cancel editing a record
* @return void
*/
function cancel()
{
$msg = JText::_( ‘Operation Cancelled’ );
$this->setRedirect( ‘index.php?option=com_hello’, $msg );
}
到现在为止,我们就全部完成了组件管理后台的开发。