joomla插件开发入门(六)
介紹
本文重點關(guān)注為管理員向當(dāng)前的靜態(tài)頁面/文章添加功能。對于管理員,當(dāng)前默認(rèn)的視圖是沒有什么用的。它并沒有做什么實質(zhì)工作– 只是顯示了存儲在數(shù)據(jù)庫中的條目。
為了讓它更具實用性,我們需要添加一些按鈕和鏈接。本文為組件擴(kuò)展內(nèi)容管理的任務(wù)。將要增加的典型任務(wù)是添加、變更和刪除。
增加互動
將在兩個層面添加互動。在管理員框架層面增加工具條及在文章自身層面增加鏈接引用和表單提交。
了解基礎(chǔ)知識,查看Joomla MVC組件開發(fā)– 第4部分– 創(chuàng)建管理員界面。
工具條
你可能已經(jīng)注意到在其它Joomla組件的管理員面板上方出現(xiàn)的工具條。我們的組件同樣也需要一個。Joomla做到這個非常簡單。我們將添加按鈕刪除記錄、編輯記錄和創(chuàng)建新記錄。我們也將添加一個顯示在工具條上的標(biāo)題。
通過向視圖中增加代碼來實現(xiàn)這些。我們使用Joomla JToolBarHelper類的靜態(tài)方法來增加按鈕。代碼如下:
JToolBarHelper::title( JText::_('Hello Manager'), 'generic.png');
JToolBarHelper::deleteList();
JToolBarHelper::editListX();
JToolBarHelper::addNewX();
這三個方法將創(chuàng)建想要的按鈕。deleteList()方法最多三個可選參數(shù)– 第一個參數(shù)是一個顯示給用戶的字符串,用來確認(rèn)他們要刪除記錄。第二個參數(shù)是發(fā)送的查詢?nèi)蝿?wù)(默認(rèn)是'remove');第三個參數(shù)是顯示在按鈕上的文本。
editListX() 和addNewX()每個方法最多兩個可選參數(shù)。第一個參數(shù)是任務(wù)(默認(rèn)值分別是edit和add),第二個參數(shù)是顯示在按鈕上的文本。
<!--[if !supportLists]-->§ <!--[endif]-->你可能已經(jīng)注意到在之前的模板中和這里都使用了JText::_ 方法。這是個方便的功能,它讓組件的翻譯更加容易。JText::_ 方法將查找組件語言文件中的字符串,并返回轉(zhuǎn)換后的字符串。如果沒有找到轉(zhuǎn)換文本,則返回你傳遞給它的字符串。如果你要將組件翻譯成其它語言,所要做的就是創(chuàng)建語言文件,并將引號內(nèi)的字符串映射為翻譯版本的字符串。
選擇框和鏈接
現(xiàn)在,我們有了按鈕。其中兩個按鈕用來處理已存在的記錄。但是,我們怎么知道該處理那條記錄呢?這需要讓用戶告訴我們。要做到這些,需要為表格添加選擇框,從而用戶能選擇明確的記錄。這在模板中實現(xiàn)。
需要向表格增加額外的列來增加選擇框。我們在已存在的兩列之間增加該列。
在列頭,我們增加一個選擇框,用來切換其下所有選擇框的選中或未選中狀態(tài):
<th width="20">
<input type="checkbox" name="toggle" value="" οnclick="checkAll(<?phpecho count( $this->items ); ?>);" />
</th>
Javascript函數(shù)checkAll內(nèi)置在Joomla的基本Javascript包中,它提供了我們想要的功能。
現(xiàn)在,我們向獨立的行增加選擇框。Joomla的JHTML類有一個方法JHTML::_(),它將為我們生成選擇框。我們向循環(huán)中增加下面的代碼行:
$checked = JHTML::_('grid.id', $i, $row->id);
這行之后:
$row=& $this->items[$i];
然后,我們在已存在的兩列之間中增加一個單元格:
<td>
<?phpecho$checked; ?>
</td>
必須先選中想要編輯的選擇框,然后再向上移動點擊編輯按鈕,這樣做不夠方便。因此,我們增加一個鏈接,這樣就會直接鏈接到greeting的編輯表單。我們在調(diào)用JHTML::_()方法之后,增加下面的代碼行來生成HTML鏈接:
$link =JRoute::_('index.php?option=com_hello&controller=hello&task=edit&cid[]='. $row->id);
然后,為顯示greeting文本的單元格加上鏈接:
<td>
<a href="<?php echo $link; ?>"><?php echo$row->greeting; ?></a>
</td>
你應(yīng)該注意到了這個鏈接指向hello控制器。這個控制器將處理greeting的數(shù)據(jù)操作。
如果你還記得前面的代碼,在表單的底部有四個隱藏的字段。第一個輸入字段是'option’。這個字段是必須的,填寫我們的組件名。第二個輸入字段是’task’。當(dāng)點擊工具欄的按鈕時,設(shè)置這個表單屬性。如果省略了這個輸入字段,會產(chǎn)生Javascript錯誤并且按鈕也無法運行。第三個輸入字段是’boxchecked’。這個字段一直跟隨當(dāng)前選中的選擇框編號。編輯和刪除按鈕將對該值進(jìn)行檢查來確保它大于0,而且如果該值沒有設(shè)置將不允許提交表單。第四個輸入字段是’ controller’。用來指定由hello控制器來處理該表單觸發(fā)的任務(wù)。
下面是完整的default.php文件源代碼:
<?phpdefined('_JEXEC') or die('Restrictedaccess'); ?>
<form action="index.php" method="post" name="adminForm">
<div id="editcell">
<table class="adminlist">
<thead>
<tr>
<thwidth="5">
<?phpecho JText::_('ID'); ?>
</th>
<thwidth="20">
<input type="checkbox" name="toggle" value="" οnclick="checkAll(<?php echo count( $this->items );?>);" />
</th>
<th>
<?phpecho JText::_('Greeting'); ?>
</th>
</tr>
</thead>
<?php
$k = 0;
for($i=0, $n=count($this->items); $i < $n; $i++)
{
$row =& $this->items[$i];
$checked = JHTML::_('grid.id', $i, $row->id);
$link = JRoute::_('index.php?option=com_hello&controller=hello&task=edit&cid[]='. $row->id);
?>
<tr class="<?php echo "row$k"; ?>">
<td>
<?phpecho$row->id; ?>
</td>
<td>
<?phpecho$checked; ?>
</td>
<td>
<a href="<?php echo$link; ?>"><?php echo$row->greeting;?></a>
</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>
現(xiàn)在hellos視圖完成了。
Getting Down and Dirty: Doing the Real Work
現(xiàn)在,Hellos視圖已經(jīng)完成,是轉(zhuǎn)向Hello控制器和模型的時候了。這里,將完成真正的工作。
Hello 控制器
Hello控制器工作時,我們的默認(rèn)控制器不會妨礙它– 它要做的一切的就是顯示視圖。
我們需要能夠處理從Hellos視圖發(fā)起的任務(wù):添加、編輯和刪除。創(chuàng)建Hello控制器(位于控制器子目錄)用來實際執(zhí)行添加、編輯和刪除單個條目。
本質(zhì)上講,添加和編輯是同樣的任務(wù):它們都是向用戶顯示一個編輯greeting的表單。唯一的不同是,添加顯示一個空白表單,而編輯顯示一個帶有數(shù)據(jù)的表單。既然它們很相似,我們將添加任務(wù)映射到編輯任務(wù)的處理中。這在我們的構(gòu)造函數(shù)中指定:
/**
* constructor(registers additional tasks to methods)
* @return void
*/
function __construct()
{
parent::__construct();
// Register Extra tasks
$this->registerTask('add', 'edit');
}
JController::registerTask方法的第一個參數(shù)是被映射的任務(wù),第二個參數(shù)是映射的目標(biāo)任務(wù)。
我們將開始處理編輯任務(wù)。對于編輯任務(wù)來講,控制器的工作是相當(dāng)簡單。所有要做的就是指定加載的視圖和布局(hello視圖和表單布局)。我們也將告訴Joomla,當(dāng)編輯greeting時禁用mainmenu。這能防止用戶離開未保存的記錄。
編輯任務(wù)的處理看起來如下:
/**
* display the editform
* @return void
*/
function edit()
{
JRequest::setVar('view', 'hello');
JRequest::setVar('layout', 'form' );
JRequest::setVar('hidemainmenu', 1);
parent::display();
}
注意:關(guān)于命名約定:入口調(diào)用程序(hello.php)來假定控制器的文件名和類名。針對這個列子,匯總?cè)缦?#xff1a;
Defaultcontroller path: …/controller.php
Defaultcontroller class name: HellosController
Requestedcontroller path …/controllers/<requestName>.php
Requestedcontroller class name: HellosController<requestName>
admin/controllers/hello.php中的控制器源代碼:
<?php
/**
* Hello Controllerfor Hello World Component
*
* @package Joomla.Tutorials
* @subpackageComponents
* @linkhttp://docs.joomla.org/Developing_a_Model-View-Controller_Component_-_Part_4
* @license GNU/GPL
*/
// No direct access
defined('_JEXEC') or die('Restricted access');
/**
* Hello HelloController
*
* @package Joomla.Tutorials
* @subpackageComponents
*/
classHellosControllerHello extends HellosController
{
/**
*constructor (registers additional tasks to methods)
* @returnvoid
*/
function__construct()
{
parent::__construct();
// Register Extra tasks
$this->registerTask('add' , 'edit');
}
/**
* displaythe edit form
* @returnvoid
*/
functionedit()
{
JRequest::setVar('view', 'hello');
JRequest::setVar('layout', 'form' );
JRequest::setVar('hidemainmenu', 1);
parent::display();
}
}
Hello 視圖
Hello視圖將顯示讓用戶編輯greeting的表單。hello視圖的顯示方法要做一些簡單的任務(wù):
<!--[if !supportLists]-->§ <!--[endif]-->從模型中獲取數(shù)據(jù)
<!--[if !supportLists]-->§ <!--[endif]-->建立工具條
<!--[if !supportLists]-->§ <!--[endif]-->將數(shù)據(jù)注入模板
<!--[if !supportLists]-->§ <!--[endif]-->調(diào)用display()方法來渲染模板
因為要在一個視圖中同時處理編輯和添加任務(wù),這變得有點復(fù)雜。在工具條中,我們要讓用戶知道他們是在添加,還是編輯。因此,我們必須確定那個任務(wù)被觸發(fā)了。
既然,已經(jīng)從模型中取得了想要顯示的數(shù)據(jù)記錄,我們就能使用這個數(shù)據(jù)來決定那個任務(wù)被觸發(fā)了。如果是編輯任務(wù),那么記錄的id字段會被設(shè)置。如果是添加任務(wù),那么id字段不會設(shè)置。這可以用來確定,我們是有一個新記錄,還是現(xiàn)有記錄。
我們添加兩個按鈕到工具條:保存和取消。雖然功能是一樣的,但是我們還是要根據(jù)是新增還是現(xiàn)有記錄,來顯示不同的按鈕。如果是新增記錄,我們將顯示取消。如果是現(xiàn)有記錄,我們將顯示關(guān)閉。
因而,我們的顯示方法如下:
/**
* display methodof 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);
}
admin/views/hello/view.html.php中的視圖源代碼:
<?php
/**
* Hello View forHello World Component
*
* @package Joomla.Tutorials
* @subpackageComponents
* @linkhttp://docs.joomla.org/Developing_a_Model-View-Controller_Component_-_Part_4
* @license GNU/GPL
*/
// No direct access
defined('_JEXEC') or die('Restricted access');
jimport('joomla.application.component.view');
/**
* Hello View
*
* @package Joomla.Tutorials
* @subpackageComponents
*/
classHellosViewHello extends JView
{
/**
* displaymethod of Hello view
* @returnvoid
**/
functiondisplay($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 itemsthe button is renamed `close`
JToolBarHelper::cancel('cancel', 'Close');
}
$this->assignRef('hello', $hello);
parent::display($tpl);
}
}
Hello 模型
我們的視圖需要數(shù)據(jù)。因而,我們需要創(chuàng)建一個模型來模擬hello。
模型將有兩個屬性:_id和_data。_id將保存greeting的id,而數(shù)據(jù)保存在_data中。
我們從構(gòu)造函數(shù)開始,它將嘗試從查詢中獲取id:
/**
* Constructor thatretrieves 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中獲取數(shù)據(jù)。第一個參數(shù)是表單的變量名稱。第二個參數(shù)是變量在未找到值時的默認(rèn)賦值。第三個參數(shù)是獲取數(shù)據(jù)方式的名稱(如:get, post),最后一個是變量強(qiáng)制轉(zhuǎn)換的數(shù)據(jù)類型。
構(gòu)造函數(shù)將cid數(shù)組的第一個數(shù)據(jù)賦值給id。
setId()方法用來設(shè)置id值。更改模型指向的id意味著id將指向錯誤的數(shù)據(jù)。因此,當(dāng)設(shè)置id時,我們將清除數(shù)據(jù)屬性:
/**
* Method to setthe hello identifier
*
* @access public
* @param int Hello identifier
* @return void
*/
function setId($id)
{
// Set id and wipe data
$this->_id = $id;
$this->_data = null;
}
最后,我們需要一個方法來獲取數(shù)據(jù):getData()
getData將檢查_data屬性是否已經(jīng)設(shè)置,如果已經(jīng)設(shè)置了,就簡單的返回該數(shù)據(jù)。否則,將從數(shù)據(jù)庫中加載數(shù)據(jù)。
/**
* Method to get ahello
* @return objectwith data
*/
function & getData()
{
// Load the data
if(empty($this->_data )){
$query = ' SELECT* FROM #__hello '.
' WHEREid = '.$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;
}
表單
現(xiàn)在,剩下的工作是建立用來填充數(shù)據(jù)的表單。既然,我們?yōu)楸韱沃付瞬季?#xff0c;那么該表單將執(zhí)行位于hello視圖模板目錄下的form.php文件。
<?phpdefined('_JEXEC') or die('Restrictedaccess'); ?>
<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>
<tdwidth="100" align="right"class="key">
<label for="greeting">
<?phpecho 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(并且是不能編輯),所以,我們在表單中默默傳遞它。
已實現(xiàn)的功能
到目前為止,我們的控制器僅能處理兩個任務(wù):編輯和添加。但是,我們也有按鈕來保存、刪除和取消記錄。我們需要編寫代碼來處理和執(zhí)行這些任務(wù)。
保存記錄
按照常理,下一步是實現(xiàn)保存記錄的功能。通常,這需要一些開關(guān)和邏輯來處理不同的情況,比如創(chuàng)建一個新記錄(INSERT查詢)和更新現(xiàn)有記錄(UPDATE查詢)之間的不同。而且,從表單獲取數(shù)據(jù)并放入查詢語句也有些復(fù)雜。
Joomla 框架為你想到了這些。JTable類讓你在不用關(guān)心SQL語句的情況下,方便地處理數(shù)據(jù)庫記錄。同時,HTML表單的數(shù)據(jù)轉(zhuǎn)移到數(shù)據(jù)庫也將變得容易。
創(chuàng)建表格類
JTable類是一個抽象類,你可以繼承子類來處理指定的表。要使用它,只需要簡單地創(chuàng)建一個JTable類的的子類,添加數(shù)據(jù)庫字段作為屬性,并且重寫構(gòu)造函數(shù)來指定表名和主鍵。
這是我們的JTable類:
<?php
/**
* Hello Worldtable class
*
* @package Joomla.Tutorials
* @subpackageComponents
* @linkhttp://docs.joomla.org/Developing_a_Model-View-Controller_Component_-_Part_4
* @license GNU/GPL
*/
// No direct access
defined('_JEXEC') or die('Restrictedaccess');
/**
* Hello Tableclass
*
* @package Joomla.Tutorials
* @subpackageComponents
*/
classTableHello extends JTable
{
/**
* Primary Key
*
* @var int
*/
var $id = null;
/**
* @var string
*/
var $greeting = null;
/**
* Constructor
*
* @paramobject Database connector object
*/
function__construct( &$db){
parent::__construct('#__hello', 'id', $db);
}
}
你會看到,我們定義了兩個字段:id字段和greeting字段。然后,我們定義了一個構(gòu)造函數(shù),其調(diào)用了父類的構(gòu)造函數(shù),并將表名(hello)、主鍵的字段名(id)和數(shù)據(jù)庫連接對象傳遞給它。
這個文件應(yīng)該叫做hello.php,放在組件管理單元的tables目錄下。
在模型中實現(xiàn)功能
現(xiàn)在,我們準(zhǔn)備向模型里面增加一個方法來保存記錄。這個方法叫做store。store()方法做三個事情:綁定表單數(shù)據(jù)到TableHello對象,檢查以確保記錄被正確組裝,保存記錄到數(shù)據(jù)庫。
這個方法如下:
/**
* Method to storea 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());
returnfalse;
}
// Make sure the hello record is valid
if(!$row->check()){
$this->setError($this->_db->getErrorMsg());
returnfalse;
}
// Store the web link table to the database
if(!$row->store()){
$this->setError($this->_db->getErrorMsg());
returnfalse;
}
returntrue;
}
這個方法被添加到hello模型。
這個方法接受一個參數(shù):我們要存儲到數(shù)據(jù)庫的數(shù)據(jù)組成的數(shù)組。稍后將會看到,從request中獲取數(shù)據(jù)很容易。
你會看到,第一行返回一個JTable對象的引用。如果表格命名正確,我們不需要指定它的名字– JModel類知道到哪里去找到它。你可能還記得,我們將表格類叫做TableHello,并把該類放到了tables目錄下的hello.php文件中。如果遵循該約定,JModel類能自動創(chuàng)建你的對象。
第二行從表單中獲取數(shù)據(jù)。用JRequest類實現(xiàn)非常容易。在本例中,我們獲取用'POST'方法提交的所有變量。這些變量以關(guān)系數(shù)組形式返回。
剩下的簡單– 綁定、檢查和存儲。bind()方法將數(shù)組的數(shù)據(jù)復(fù)制到對應(yīng)表格對象的屬性。在本例中,將獲取的id和greeting的值,復(fù)制到TableHello對象。
check()方法將執(zhí)行數(shù)據(jù)校驗。在JTable()類中,這個方法簡單地返回true。雖然,現(xiàn)在沒有為我們提供任何價值,但是在將來使用TableHello類時,我們就可以通過調(diào)用這個方法進(jìn)行數(shù)據(jù)檢查。在TableHello類中,我們可以重寫該方法,來執(zhí)行適合的檢查。
store()方法將對象中的數(shù)據(jù)存儲到數(shù)據(jù)庫。如果id是0,它將創(chuàng)建一個新記錄(INSERT),否則它將更新現(xiàn)有記錄(UPDATE)。
向控制器添加任務(wù)
現(xiàn)在,我們準(zhǔn)備向控制器中添加任務(wù)了。既然,我們觸發(fā)的任務(wù)叫做'save',那么我們的方法必須被命名為'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);
}
我們所要做的就是獲取模型,并調(diào)用store()方法。然后,我們使用setRedirect()方法,重定向返回到greeting列表。我們也順便傳遞一個信息,以顯示在頁面的頂部。
刪除記錄(在模型中實現(xiàn)該功能)
在模型中,我們檢索要刪除的ID列表,并調(diào)用JTable類來刪除它們。
具體如下:
/**
* Method to deleterecord(s)
*
* @access public
* @return boolean True on success
*/
function delete()
{
$cids = JRequest::getVar('cid', array(0), 'post', 'array');
$row =& $this->getTable();
foreach($cidsas$cid){
if(!$row->delete($cid)){
$this->setError($row->getErrorMsg());
returnfalse;
}
}
returntrue;
}
我們調(diào)用JRequest::getVar()方法從request中獲取數(shù)據(jù),然后調(diào)用$row->delete()方法刪除每一行。我們可以在模型中保存錯誤消息,如果需要,可以在后面再獲取它們。
在控制器中處理刪除任務(wù)
這和處理保存任務(wù)的save()方法類似:
/**
* remove record(s)
* @return void
*/
function remove()
{
$model = $this->getModel('hello');
if(!$model->delete()){
$msg = JText::_('Error: One or MoreGreetings Could not be Deleted');
}else{
$msg = JText::_('Greeting(s) Deleted');
}
$this->setRedirect('index.php?option=com_hello', $msg);
}
取消編輯操作
我們?yōu)榱巳∠庉嫴僮?#xff0c;所要做的就是重定向返回到主視圖:
/**
* cancel editing arecord
* @return void
*/
function cancel()
{
$msg = JText::_('Operation Cancelled');
$this->setRedirect('index.php?option=com_hello', $msg);
}
結(jié)論
現(xiàn)在,我們已經(jīng)實現(xiàn)了一個基本的組件后端。我們能夠編輯前端顯示的條目。我們也展示了模型、視圖和控制器之間的互動。我們還展示了如何擴(kuò)展JTable類,來方便地訪問數(shù)據(jù)庫中的表。還可以看到如何使用JToolBarHelper來創(chuàng)建組件的按鈕欄,讓組件變得標(biāo)準(zhǔn)化。
(全部完)
轉(zhuǎn)載于:https://www.cnblogs.com/ikodota/articles/2220517.html
總結(jié)
以上是生活随笔為你收集整理的joomla插件开发入门(六)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: postgres使用dblink
- 下一篇: Java文件非法字符