Joomla Component study
จาก Wiki2
เนื้อหา |
Introduction
- เรียนจากตำราชื่อ Packt - Learning joomla 1.5 Extension development
- สมมุติว่าเราจะสร้าง component ชื่อ reviews หรือ com_reviews เพื่อสร้างระบบประเมินร้านอาหารหรือ Restaurant ใน Joomla ที่ติดตั้งบน Localhost ใต้ Directory ชื่อ Joomla
- การสร้าง component สำหรับ Joomla เริ่มจากสร้าง Folder และ File ที่จำเป็นสำหรับ Component ซึ่งสามารถสร้างได้สองวิธีคือ
- สร้างด้วยเว็บไซร์ที่ให้บริการทำ MVC Component template ซึ่งจะให้ Zip File ของ Blank Component ซึ่งสามารถนำมา Install เหมือน component ทั่วไป วิธีนี้สะดวกมาก และระบบยังเขียน Header Comment ให้, Register component ให้เป็นอย่างดี เหลือแต่เขียน Code ให้ระบบทำงานเท่านั้น
- Free MVC Component template generator for Joomla component
- เมื่อได้ Zip File จากเว็บที่ให้บริการนั้นมา ก็นำมา install ใน Joomla ซึ่งจะได้
- Directory ต่างๆที่จำเป็น
- File ที่จำเป็น เช่น PHP และ XML ซึ่งมี Header สำหรับ อธิบาย Component ของเรา
- รวมถึงการ Register Component ลงใน Database เป็นวิธีที่สะดวกที่สุด
- อีกวิธีคือสร้างด้วยมือ ซึ่งจะแสดงรายละเอียดดังต่อไปนี้
- สร้างด้วยเว็บไซร์ที่ให้บริการทำ MVC Component template ซึ่งจะให้ Zip File ของ Blank Component ซึ่งสามารถนำมา Install เหมือน component ทั่วไป วิธีนี้สะดวกมาก และระบบยังเขียน Header Comment ให้, Register component ให้เป็นอย่างดี เหลือแต่เขียน Code ให้ระบบทำงานเท่านั้น
Tools ช่วยอำนวยความสะดวก
- Editor ใช้ NetBeans IDE 6.9.1 เป็น editor โดยกำหนดให้ Joomla ทั้ง Site เป็น Project จะทำให้เรียกใช้ Class และ API ของ Joomla ได้สะดวก การแก้โปรแกรมก็จะง่ายขึ้น
- ควรติดตั้ง Extension ชื่อ Jumi ไว้ด้วยเพื่อไว้ Test Script สั้นๆว่าทำงานได้หรือไม่ ก่อนใส่ใน Component
- หากทำบน Hosting ควรติด Extension ชื่อ eXtplorer ไว้ด้วยเพราะช่วยในการ Browse File/directory, upload, download, set permission, edit file ฯลฯ
- Extension ชื่อ J!Dump ช่วยในการ Debug code โดยให้เราเห็น Variable ขณะ Run Program Joomla http://extensions.joomla.org/extensions/miscellaneous/development/1509/details ควรติดตั้งไว้ก่อนการเรียนนะครับ แล้วแทรก Code ตังตัวอย่าง ใน Code ที่เราเขียน นะครับ
- dump(JApplicationHelper::getPath( 'toolbar_html' ), "Path to toolbar html"); ดูค่าที่ Return จาก Function getPath ของ Class JApplicationHelper
- dump($task,"Task from URL"); ดูค่าใน Variable
- dumpTrace(); เพื่อดูว่าโปรแกรมเรียกใช้ อะไรมาบ้าง
- Tools อื่นใน http://extensions.joomla.org/extensions/tools
- Module Wizard ช่วยสร้าง Module ให้ง่ายขึ้น
- Plugins Wizard ช่วยสร้าง Plugins ให้ง่ายขึ้น
- jhttp_Scan เช็คดูว่ามี File ใดใน Joomla ที่ไม่ป้องกัน Direct Access
- J!Build is an Apache Ant build file to quickly make extension installer packages. Instead of manually making zips each time you want to test or distribute a new version of your extension, you can use this script to do it automatically
Create Folder
- สร้าง Folder ที่ Front end และ Back end ตามชื่อ Component ที่จะสร้าง
- Front end = joomla/components/com_reviews
- Back end = joomla/administrator/components/com_reviews
Entry file
- สร้าง File แรกที่ถูกเรียกใช้ อยู่ใน Folder ที่สร้างในตอนแรกคือ
- Front end = reviews.php
- Back end = admin.reviews.php
Security Start
- File PHP ทุก File จะต้องขึ้นต้นด้วย defined( '_JEXEC' ) or die( 'Restricted access' );
- เพื่อป้องกันไม่ให้การเรียก File โดยตรงไม่ฝ่าน Joomla
- ทุกๆ Folder จะต้องสร้าง File ชื่อ index.html ทิ้งไว้ป้องกัน Directory Browse
Access your component
URL/Direct call
- Front end = http://localhost/joomla/index.php?option=com_reviews ซึ่งจะเรียก File joomla/components/com_reviews/reviews.php ขึ้นมาใช้
- Back end = http://localhost/joomla/administrator/index.php?option=com_reviews ซึ่งจะเรียก File joomla/administrator/components/com_reviews/admin.reviews.php ขึ้นมาใช้
Registering your component
การจะเรียน Component ขึ้นมาใช้จาก Joomla User interface จะต้องให้ Joomla รู้ว่ามี Component Review ในระบบโดยสร้าง Record ใน Table jos_components ก่อน
ซึ่งมีรายละเอียดดัง Code ต่อไปนี้
INSERT INTO jos_components (name, link, admin_menu_link, admin_menu_alt, 'option', admin_menu_img, params) VALUES ('Restaurant Reviews', 'option=com_reviews', 'option=com_reviews', 'Manage Reviews', 'com_reviews', 'js/ThemeOffice/component.png', );
หรือ
- name = 'Restaurant Reviews'
- link = 'option=com_reviews'
- admin_menu_link = 'option=com_reviews'
- admin_menu_alt = 'Manage Reviews'
- option= 'com_reviews'
- admin_menu_img = 'js/ThemeOffice/component.png'
- params = ""
- นอกจากนั้นให้ Field enabled = 1 ส่วน Field อื่นๆเป็น 0 หรือไม่ต้องใส่อะไร
หลังจาก Add Record แล้วจะเห็นชื่อของ Component ของเราทาง menu Back end>components>Restaurant Reviews ส่วนทาง Front end เราจะต้องสร้าง Menu ใหม่ ซึ่งจะเห็น Component ของเราเป็น Menu Type คลิกที่ Menu ใหม่จะเห็น Component ใหม่ของเรา อาจทดลองเขียน Code ง่ายๆเช่น echo "This is back end of com_reviews" ; หรือ echo "this is front end of com_reviews"; ใน Entry file ข้างต้นนะครับ
สร้าง Toolbars ให้ Backend
ปกติใน Back end เราจะเห็น Component จะมี Tool bar เช่น New, Edit ฯลฯ ซึ่งจะอยู่ใน File 2 files คือ
- toolbar.reviews.html.php
- toolbar.reviews.php
ซึ่งเก็บไว้ใน directory joomla/administrator/components/com_reviews
toolbar.reviews.html.php
File นี้เป็นการ Define Class TOOLBAR_reviews ซึ่งจะมี Tool bar icon อะไรบ้างสำหรับกรณีที่ task เป็น New และ Default
ซึ่งจะอาศัย Class JToolBarHelper ใน Joomla Framwork สร้าง Tool bar icon ต่างๆให้เป็น HTML ใน Table ซึ่ง File นี้จะถูก Include ด้วย File toolbar.reviews.php
<?php
defined( '_JEXEC' ) or die( 'Restricted access' );
class TOOLBAR_reviews {
function _NEW() {
JToolBarHelper::title( JText::_( 'Restaurant Reviews (new)' ),'generic.png' );
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();
}
}
?>
toolbar.reviews.php
File นี้จะเช็คดูว่า Back end ของ Component ถูกเรียกใช้เพื่อให้ทำอะไร (task) โดยดูจากตอนท้ายของ URL ที่เรียกใช้ และเลือก Function ใน class TOOLBAR_reviews มาทำงาน เช่น
- http://localhost/joomla/administrator/index.php?option=com_reviews จะแสดง Tool bar ตัวที่เป็น Default
- แต่หาก URL เป็น http://localhost/joomla/administrator/index.php?option=com_reviews&task=new จะแสดง Tool bar icon ของ function function _NEW() class TOOLBAR_reviews (โปรดสังเกตุ &task=new ตอนท้ายสุดของ URL)
โดย File นี้จะมี Code ดังนี้
<?php
defined( '_JEXEC' ) or die( 'Restricted access' );
require_once( JApplicationHelper::getPath( 'toolbar_html' ) );
switch($task)
{
case 'edit':
case 'new':
TOOLBAR_reviews::_NEW();
break;
default:
TOOLBAR_reviews::_DEFAULT();
break;
}
?>
คำสั่ง require_once( JApplicationHelper::getPath( 'toolbar_html' ) ); จะเป็นการ Include File ชื่อ toolbar.reviews.html.php คำสั่งนี้เป็นการเรียกใช้ Class JApplicationHelper เพื่อเอาทั้งชื่อและ Path ของ File toolbar.reviews.html.php ซึ่งดีตรงที่ ใช้ได้ code นี้กับชื่อของ Component อื่นๆได้
หากคุณคลิกขวาที่ icon ต่างๆแล้ว copy link มาดูจะเห็นว่ามี Task Variable ต่างๆต่อท้ายที่ URL เช่น http://localhost/joomla/administrator/index.php?option=com_reviews&task=new# ซึ่งในตอนต่อไปเราจะมาเขียน Form รองรับ Task ต่างๆเหล่านั้น
note on MVC
การที่สร้างสอง File แล้วใช้ Include แทนที่จะใช้ File เดียวกันไปเลยเพราะมันเป็นวิธีในการแยก Code ที่ใช้ทำงาน (Controller) ออกจาก Code ที่ใช้แสดงผล HTML (View) ตามวิธีของ MVC และสะดวกในการ Share Code ใช้ในหลายตำแหน่งของโปรแกรมด้วย
สร้าง Database table
สิ่งแรกที่เราจะใน Application นี้คือ สร้าง Table ไว้เก็บการ Review ร้านอาหาร ใส่ใน Database เดียวกับ Joomla ด้วย phpMyAdmin โดย Run Query ต่อไปนี้
CREATE TABLE IF NOT EXISTS `jos_reviews` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `address` varchar(255) NOT NULL, `reservations` varchar(31) NOT NULL, `quicktake` text NOT NULL, `review` text NOT NULL, `notes` text NOT NULL, `smoking` tinyint(1) unsigned NOT NULL DEFAULT '0', `credit_cards` varchar(255) NOT NULL, `cuisine` varchar(31) NOT NULL, `avg_dinner_price` tinyint(3) unsigned NOT NULL DEFAULT '0', `review_date` datetime NOT NULL, `published` tinyint(1) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
สร้าง Table class
เราไม่ต้องเขียนโปรแกรมที่ทำงานกับ Table ที่เราสร้างขึ้นทั้งหมดเอง เพราะ Joomla Framework มี JTable class ที่มี Function ทำงานเหล่านั้นให้ เช่น creating, reading, updating, และ deleting records โดยเราต้องทำ Class Extension ของ JTable Class ชื่อ TableReview class โดยสร้าง File ชื่อ review.php ใน Directory joomla/administrator/components/com_reviews/table มี Code ดังต่อไปนี้
<?php
defined('_JEXEC') or die('Restricted access');
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 );
}
}
?>
ส่วน Code ตอนท้าย คือการ Override Class constructor ของ JTable ดังตัวอย่าง
function __construct(&$db)
{
parent::__construct( '#__reviews', 'id', $db );
}
- __ คือ Table prefix ในที่นี้คือ jos_ แต่การเขียนแบบนี้ทำให้ Code Portable กว่าการใช้ jos_
หลังจากการ Extent Class JTable ทำให้ Class TableReview มี Function bind(), store(), load(), delete() และ Function อื่นมาใช้ โดยเราไม่ต้องเขียนเอง เป็นความสะดวกของการใช้ Joomla Framework
สร้าง Review Form
สำหรับให้ผู้ใช้ป้อนข้อมูลการ Review ร้านอาหาร ซึ่งจะสร้างเป็นสอง File เพื่อแยก HTML (View) ออกจาก Controller code เป็นสอง File ที่เราสร้างไว้ก่อนหน้านี้ ซึ่งอยู่ใน Directory joomla/administrator/components/com_reviews ดังต่อไปนี้
- admin.reviews.php
- admin.reviews.html.php
admin.reviews.php
<?php
defined( '_JEXEC' ) or die( 'Restricted access' );
require_once( JApplicationHelper::getPath( 'admin_html' ) );
JTable::addIncludePath(JPATH_COMPONENT.DS.'tables');
switch($task)
{
case 'new':
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', 'smoking',
'class="inputbox"', $row->smoking);
$lists['published'] = JHTML::_('select.booleanlist', 'published',
'class="inputbox"', row->published);
HTML_reviews::editReview($row, $lists, $option);
}
?>
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">
<fieldset class="adminform">
<legend>Details</legend>
<table class="admintable">
<tr>
<td width="100" align="right" class="key">
Name:
</td>
<td>
<input class="text_area" 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>
<input class="text_area" 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>
<?php
echo $lists['reservations'];
?>
</td>
</tr>
<tr>
<td width="100" align="right" class="key">
Quicktake:
</td>
<td>
<?php
echo $editor->display( 'quicktake', $row->quicktake,'100%', '150', '40', '5' );
//dump($editor->display( 'quicktake', $row->quicktake,'100%', '150', '40', '5' ),'editor ');
?>
</td>
</tr>
<tr>
<td width="100" align="right" class="key">
Review:
</td>
<td>
<?php
echo $editor->display( 'review', $row->review ,
'100%', '250', '40', '10' )
?>
</td>
</tr>
<tr>
<td width="100" align="right" class="key">
Notes:
</td>
<td>
<textarea class="text_area" cols="20" rows="4"
name="notes" id="notes" style="width:500px"><?php
$row->notes; ?></textarea>
</td>
</tr>
<tr>
<td width="100" align="right" class="key">
Smoking:
</td>
<td>
<?php
echo $lists['smoking'];
?>
</td>
</tr>
<tr>
<td width="100" align="right" class="key">
Credit Cards:
</td>
<td>
<input class="text_area" 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>
<input class="text_area" 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>
$<input class="text_area" 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>
<input class="inputbox" 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>
<?php
echo $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
}
}
?>
Front End
Problem with Cache
พบว่าหลังจากแก้โปรแกรมแล้ว หน้าจอ Joomla Front end ไม่เปลี่ยนตาม อาจจะเป็นเพราะ Cache ใน Browser และ Cache ใน Joomla server ยังหาวิธีแก้ที่ชัดเจนไม่ได้ แต่เท่าที่ทดลองไปแล้วคือ
- Cache ใน Joomla server ใน Global Configuration>System>Cache Setting = No
- Firefox Cache clear โดย Edit>Preference>Privacy>Clear your recent history หรือ Ctrl+F5
- แก้ใข URL เอา &Itemid=59 ที่ท้าย URL ออก
- ไปที่ Home ก่อนแล้วแล้วกลับมาดูอีกที
Component Menu Group and Type Study
Module Creation
การสร้าง Module เหมือนการสร้าง component คือต้องมีการสร้าง Folder และ Register ลงใน Jos_module table ง่ายกว่าการสร้าง Component และการใช้ Parameter ก็สะดวกมาก ไม่ยากอยางที่กลัวเลย
