久久精品水蜜桃av综合天堂,久久精品丝袜高跟鞋,精品国产肉丝袜久久,国产一区二区三区色噜噜,黑人video粗暴亚裔

Gallery:模塊開發(fā)教程

來自站長百科
Firebrance討論 | 貢獻(xiàn)2008年11月27日 (四) 17:15的版本
跳轉(zhuǎn)至: 導(dǎo)航、? 搜索

一般注釋

部分內(nèi)容經(jīng)許可取自:http://txtdump.com/g2dev/

此處的代碼針對Gallery2.2已經(jīng)過更新。

模塊創(chuàng)建腳本(Module Creator Script)

該教程將幫助你從零開始創(chuàng)建所有的模塊文件。你還可通過命令行運(yùn)行g(shù)allery2目錄的php lib/tools/creator/create-module.php來新建模塊。

注: 你必須有G2開發(fā)者整合包或從svn/nightly snapshot進(jìn)行安裝以獲得lib/tools/creator。

G2開發(fā):介紹

前言

初次開發(fā)G2時(shí),你可以嘗試多花點(diǎn)時(shí)間來理解基本知識。此教程中我們會(huì)從最基本的開始,沒用過PHP的人都可以學(xué)會(huì)編寫模塊代碼,并且能做大做好。

G2的“理”和“實(shí)”

G2幾乎實(shí)現(xiàn)了代碼和設(shè)計(jì)之間的完全分離,以及一套可插模塊的系統(tǒng)。那么這對你意味著什么呢?通過使用G2的API(應(yīng)用程序編程接口)你可以向G2添加新的功能而無需對核心代碼做任何修改。

在我想修改G2時(shí)的第一種沖動(dòng)就是找到有問題的代碼,然后將其修改為我需要的形式。但是這只是一個(gè)短期的權(quán)宜之計(jì),在將來,尤其是你需要升級核心代碼庫時(shí),麻煩就來了。實(shí)現(xiàn)某種修改或新特點(diǎn)的更有效途徑就是編寫模塊。開始可能會(huì)多花費(fèi)你一些時(shí)間,但之后你就會(huì)意識到維護(hù)好比10個(gè)模塊,就如同修改幾行語句以符合新版本的API那樣輕松。

G2如何工作?

在開始之前,你至少需要明白G2的工作方式。比如,當(dāng)點(diǎn)擊邊欄中的"成員列表(Member List)"鏈接是發(fā)生什么?

  1. 請求送達(dá)main.php,即G2主要的包裝腳本。它會(huì)看到后置到"main.php"的URL部分,"?g2_view=members.MembersList",然后獲知你想載入"members"模塊并顯示視圖"MembersList"(一個(gè)視圖就是一個(gè)動(dòng)態(tài)G2頁面)。
  2. "members"模塊從modules/members被載入,并被告知顯示"MembersList"視圖。模塊載入一個(gè)名為MembersList.inc 的文件,它會(huì)使用G2 API來聯(lián)系數(shù)據(jù)庫并準(zhǔn)備所有所需信息(membername,id,email等)。
  3. 默認(rèn)外觀主題被載入并被指示顯示一個(gè)模塊頁面。在編寫模塊時(shí)你無需為此擔(dān)憂,只要注意外觀主題可以在你的模塊內(nèi)容周圍顯示東西即可,比如頭/尾等。
  4. 對應(yīng)模板,modules/members/templates/MembersList.tpl,被載入而數(shù)據(jù)則被傳送至此。該模板使用生成一個(gè)表格,事項(xiàng)處理就完成了。

如你所見,在此過程中有若干相異部分并各司其職。除了個(gè)別例外情況,不將復(fù)雜代碼包括進(jìn)模板,或?qū)⒛0鍞?shù)據(jù)置入PHP代碼中。一旦你理解此重要概念,G2的開發(fā)就變得更為簡單了。

你已經(jīng)看了這么多啦!真不簡單!接下來我們來為G2創(chuàng)建模塊。我打包票,絕對不難。

模塊目錄結(jié)構(gòu)

modules/$modulename/module.inc

此為各模塊所具有的入口點(diǎn)。它定義模塊的身份以及職能。此為所有模塊所必須具有的文件,當(dāng)然也是唯一必須的文件。其余文件則根據(jù)模塊職能不同而有所取舍。

modules/$modulename/$viewname.inc

頁面被稱為"視圖(view)"。各視圖都具有各自的.inc文件。該文件的文件名與視圖相同。如果視圖可以執(zhí)行任何動(dòng)作的話(即可通過按鈕完成一些行為),那么該文件還會(huì)具有一個(gè)"控制器(controller)"類別,用以處理這些動(dòng)作。

modules/$modulename/templates/$viewname.tpl

各視圖的實(shí)際HTML位于一個(gè)模板文件中,該文件具有與視圖相同的文件名。

modules/$modulename/templates/blocks/blocks.inc

此為一PHP文件,它告知各外觀主題哪些為可用區(qū)塊以及針對各區(qū)塊所需載入的模板文件。該文件并非區(qū)塊運(yùn)行所必需的,但能使得這些區(qū)塊可被外觀主題用于"邊欄區(qū)塊(sidebar blocks)"及"相片區(qū)塊(photo blocks)"等的設(shè)定之中。

modules/$modulename/templates/blocks/*.tpl

包含自blocks.inc 所定義區(qū)塊的模板代碼。

modules/$modulename/Callbacks.inc

該文件為各模塊callback加載所用。定義區(qū)塊的模塊可使用此文件加載區(qū)塊數(shù)據(jù)。

modules/$modulename/Preloads.inc

該文件為各模塊preload加載所用。定義區(qū)塊的模塊可使用此文件指定區(qū)塊所需的css或javascript。

modules/$modulename/classes/*Helper.class

*Helper.class文件為可選的。它們被用來組織用于多個(gè)視圖內(nèi)容的代碼,或是將大塊代碼分解成易于管理的小塊。

modules/$modulename/classes/*Interface.class

接口針對多個(gè)模塊共享某種常見方法以完成相似任務(wù)之用。比如,Search模塊實(shí)現(xiàn)的search接口,其他模塊可添加搜索(search)功能。

modules/$modulename/classes/Maps.xml

數(shù)據(jù)庫表方案被保存在XML文件中以保證其可移植性。Gallery則會(huì)讓它與各類數(shù)據(jù)庫引擎兼容協(xié)作。僅當(dāng)模塊在數(shù)據(jù)庫中保存數(shù)據(jù)的情況下才會(huì)用到它。

modules/$modulename/test/phpunit/*Test.class

這些是模塊的單元測試。訪問Gallery中的lib/tools/phpunit/index.php來運(yùn)行單元測試。這些自動(dòng)化的測試旨在確認(rèn)模塊能按預(yù)期運(yùn)行。它們的編寫需要花費(fèi)時(shí)間,但能保證Gallery核心更改或你自己對模塊作出的修改不會(huì)對模塊造成破壞。

modules/$modulename/po/*.po

這些是模塊中文本在其他語言中的翻譯。

modules/$modulename/locale/*

這些為Gallery實(shí)際所使用的經(jīng)編譯的翻譯。

啞模塊編碼

前言

現(xiàn)在你應(yīng)該基本了解了G2系統(tǒng),那么我們就開始深入下去吧,比如編寫一個(gè)基礎(chǔ)模塊。

注: 確保PHP能顯示語法錯(cuò)誤和其他問題。參見:針對Gallery開發(fā)者的PHP設(shè)定,尤其注意一下gallery2/config.php中的display_errors

模塊結(jié)構(gòu)

G2中的所有模塊在modules/目錄下都必須具有自己的目錄,并在該目錄下含有一個(gè)module.inc文件。用你習(xí)慣的方法創(chuàng)建它們。將目錄命名為tutorial1

提示:在*nix系統(tǒng)中。touch命令可用來創(chuàng)建空文件。

就是這樣!現(xiàn)在你就有這些了:

modules/tutorial1/           (目錄)
modules/tutorial1/module.inc (空文件)

module.inc

module.inc是模塊最'核心'的部分。它告知G2諸如模塊名稱,描述及版本一類的信息,以及其他龐雜的細(xì)枝末節(jié)。.

首先我們表明此為一PHP腳本。很簡單,如此開頭即可:

<?php

現(xiàn)在,將其粘貼到G2標(biāo)準(zhǔn)樣版文件中。

/*
 * Gallery – 基于web的相片相冊查看器和編輯器
 * Copyright (C) 2000-2006 Bharat Mediratta
 *
 * 該程序?yàn)槊赓M(fèi)的,你可以對其做修改
 * 受GNU General Public License條款約束
 * 由Free Software Foundation發(fā)布;許可的第二版,或者說是
 * 以后的版本。
 *
 * 我們希望該應(yīng)用程序能有用處,但
 * 不打包票;也不能保證其
 * 適銷性或針對特殊目的的適用性。更多信息請參見GNU
 * General Public License。
 *
 * 在獲取此程序的同時(shí),你應(yīng)當(dāng)也收到了
* GNU General Public License;如果沒有的話,請聯(lián)系Free Software
 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
 */

接下來我們要填入一些管理數(shù)據(jù)。你不需要進(jìn)行任何修改。該數(shù)據(jù)不會(huì)為模塊所用,但G2會(huì)將其用于管理/文檔處理。

/**
 * Tutorial1 module
 *
 * My first module!
 *
 * @package Tutorial1
 * @author Your Name <you@email.com>
 * @version $Revision$ $Date: 2006/01/02 07:58:13 $
 */

接下來,我們告知G2我們的tutorial1模塊將擴(kuò)展GalleryModule。

class Tutorial1Module extends GalleryModule {

現(xiàn)在我們需要填入該模塊所需的數(shù)據(jù)。這將在模塊的Tutorial1Module函數(shù)中完成。

    function Tutorial1Module() {
        global $gallery;

        $this->setId('tutorial1');
        $this->setName($gallery->i18n('Tutorial Module 1'));
        $this->setDescription($gallery->i18n('My first module.'));
        $this->setVersion('0.9.0');
        $this->setGroup('data', $gallery->i18n('Extra Data'));
        $this->setCallbacks('');
        $this->setRequiredCoreApi(array(7, 10));
        $this->setRequiredModuleApi(array(3, 2));
    }

前三行是自描述的。setId值必須符合模塊的目錄名。$gallery->i18n行允許文本字段被翻譯成其他語言。setVersion字段則只是用于模塊的版本號,我們使用0.9.0。setGroup指的是站點(diǎn)管理頁面中模塊將被放入的組。我們還不需要設(shè)定callback,因此這里先空著不管。

我們的RequiredCoreApiRequiredModuleApi版本必須符合G2所提供的版本,不然的話就會(huì)造成破壞。你想知道G2最新的API版本?檢查G2 Team的某個(gè)模塊并使用它的版本號。這里我們會(huì)使用CoreAPI v 7.10和ModuleAPI v 3.2。

注: Gallery 2.3模塊會(huì)在構(gòu)建式里多出一行:

        $this->_templateVersion = 1;
Gallery 2.3的外觀主題可以覆蓋模塊的tpl文件。當(dāng)模塊新版本發(fā)布時(shí)請注意增加此數(shù)字,因?yàn)槠湓趖pl文件中的修改無法與舊版本兼容。外觀主題覆蓋僅當(dāng)模板版本相符時(shí)才能使用。注意,如果某人安裝了Gallery2.2.x或更早版本的模塊,而此方法不存在時(shí),模塊構(gòu)建式中的此代碼就不會(huì)使用$this->setTemplateVersion(1)。模塊構(gòu)建式中的PHP錯(cuò)誤將會(huì)妨礙Gallery API的版本檢查。

完成了,使用如下內(nèi)容做結(jié)束:

}
?>

整個(gè)module.inc代碼可在此找到。

模塊的安裝和激活

祝賀你,你已經(jīng)編寫完成了第一個(gè)G2模塊!但目前你的模塊還無法實(shí)際使用。如果不啟用功能的話,就沒有任何用處;所以,如果沒有問題的話,你可以登入站點(diǎn)管理界面,點(diǎn)擊插件(Plugins),下拉到額外數(shù)據(jù)(Extra Data)部分,然后安裝并激活(在此還可以進(jìn)行禁用和卸載)你的模塊。很有意思,是不?

你剛剛創(chuàng)建完成了一個(gè)完全兼容且完美的G2模塊。你會(huì)發(fā)現(xiàn)將來所制作的模塊結(jié)構(gòu)都是如此。好吧,是時(shí)候鼓勵(lì)一下自己了,接下來的部分將教會(huì)你創(chuàng)建使用模板引擎的模塊。

顯示靜態(tài)頁面的模塊

前言

現(xiàn)在你知道如何創(chuàng)建一個(gè)G2模塊了,那么就讓我們更深一步,創(chuàng)建使用模板引擎的模塊以顯示靜態(tài)頁面。

模塊結(jié)構(gòu)

首先創(chuàng)建一個(gè)modules/tutorial2目錄。我們將從之前的模塊繼續(xù)。將舊的module.inc復(fù)制到新目錄中,但請確保將tutorial1的所有實(shí)例修改為tutorial2,Tutorial1修改為Tutorial2。

另外,創(chuàng)建如下的文件和目錄,目前這些文件都可以為空。

modules/tutorial2/MyPage.inc
modules/tutorial2/templates/
modules/tutorial2/templates/MyPage.tpl

module.inc

我們不需要對module.inc做任何修改。MyPage.inc文件存在就允許G2使用它。繼續(xù)并打開MyPage.inc文件。

MyPage.inc

在G2中是無法直接訪問模板的。你必須使用一個(gè)"視圖(view)",它將會(huì)準(zhǔn)備所有必須的數(shù)據(jù)然后載入模板。MyPage.inc就是這樣一種視圖。

現(xiàn)在開始粘貼一般的G2樣板文件。

<?php
/*
* Gallery – 基于web的相片相冊查看器和編輯器
 * Copyright (C) 2000-2006 Bharat Mediratta
 *
 * 該程序?yàn)槊赓M(fèi)的,你可以對其做修改
 * 受GNU General Public License條款約束
 * 由Free Software Foundation發(fā)布;許可的第二版,或者說是
 * 以后的版本。
 *
 * 我們希望該應(yīng)用程序能有用處,但
 * 不打包票;也不能保證其
 * 適銷性或針對特殊目的的適用性。更多信息請參見GNU
 * General Public License。
 *
 * 在獲取此程序的同時(shí),你應(yīng)當(dāng)也收到了
* GNU General Public License;如果沒有的話,請聯(lián)系Free Software
 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
 */

填入其他標(biāo)準(zhǔn)數(shù)據(jù)。

/**
 * 該視圖顯示一個(gè)靜態(tài)頁面。
 *
 * @package Tutorial2
 * @subpackage UserInterface
 * @author Your Name <you@email.com>
 * @version $Revision$ $Date: 2006/01/05 07:00:00 $
 */

你應(yīng)該對module.inc的結(jié)構(gòu)不陌生吧,那你就應(yīng)該知道接下來要做的了。我們希望使用你自己的類別對GalleryView類別進(jìn)擴(kuò)展。

class MyPageView extends GalleryView {

類別名稱必須與你的*.inc文件名稱相同,并以"View"結(jié)尾?,F(xiàn)在,我們的模塊還不需要做任何數(shù)據(jù)操作,我們只需要2個(gè)函數(shù)。其中主要的一個(gè)就是loadTemplate。

    /**
     * @see GalleryView::loadTemplate
     */
    function loadTemplate(&$template, &$form) {
        global $gallery;

loadTemplate函數(shù)中,我們告知G2在載入模板前所需做的所有事情。

對于我們的頁面,將載入Gallery頂層相冊,所以我們就可以顯示有關(guān)它的一些信息了。

        list ($ret, $albumId) = GalleryCoreApi::getDefaultAlbumId();
        if ($ret) {
            return array($ret, null);
        }

        list ($ret, $album) = GalleryCoreApi::loadEntitiesById($albumId);
        if ($ret) {
            return array($ret, null);
        }
注: 在Gallery 2.1.x中,return array($ret, null);應(yīng)為return array($ret->wrap(__FILE__, __LINE__), null);

將這些呼叫的結(jié)構(gòu)記錄下來,這相當(dāng)重要,因?yàn)樵诤芏郍2代碼中都要重復(fù)使用它。另外注意我們已加載了根相冊,但還沒有對其做任何操作。現(xiàn)在將這些數(shù)據(jù)用于我們的模板。

        $template->setVariable('MyPage',
            array('album' => (array)$album, 'showAlbum' => true));

我們用以顯示頁面的數(shù)據(jù)應(yīng)當(dāng)被給予$template->setVariable。無論何時(shí)模板數(shù)據(jù)被添加一個(gè)"實(shí)體",它都應(yīng)當(dāng)被轉(zhuǎn)換為上面所示的數(shù)組。

現(xiàn)在讓我們繼續(xù),來加載模板。

        return array(null,
                     array('body' => 'modules/tutorial2/templates/MyPage.tpl'));
    }

如果我們能走到這一步,那么所作的這些都成功了。所以,我們告知G2成功了,并載入合適的模板文件。

你是否邊欄上的注意到back to ____導(dǎo)航鏈接了?讓我們將此特點(diǎn)整入我們的模塊中吧。要達(dá)到此目的,我們要?jiǎng)?chuàng)建另一個(gè)函數(shù)。

    /**
     * @see GalleryView::getViewDescription()
     */
    function getViewDescription() {
        list ($ret, $module) = GalleryCoreApi::loadPlugin('module', 'tutorial2');
        if ($ret) {
            return array($ret, null);
        }

        return array(null, $module->translate('My Page'));
    }

你可以將"My Page"改為你中意的明朝。最后,我們結(jié)束該類別以及PHP腳本。

}
?>

這么簡單的一個(gè)任務(wù)看起來卻用到了這么多代碼,但這些代碼可以在你今后的模塊編寫中反復(fù)使用的。你會(huì)發(fā)現(xiàn),一旦掌握了基本模塊的編碼手段,就能輕松如意地編寫更大更豐富的模塊了。

現(xiàn)在是最后一個(gè)文件了,模板。

templates/MyPage.tpl

你應(yīng)該能記得,loadTemplate()函數(shù)中的最后一個(gè)呼叫是模板的加載。G2使用Smarty模板引擎,這能提供很棒的代碼與設(shè)計(jì)間的分離。 You'll find that you can use standard HTML in the template files, which makes them much easier to edit.

Let's get started.

{*
 * $Revision$
 * 如果你想對此文件進(jìn)行自定義的話,請勿直接編輯它,因?yàn)樵趯砩墪r(shí)
 * 會(huì)將其覆蓋掉。請將其復(fù)制到一個(gè)名為"local"的新建文件夾中再進(jìn)行編輯
 * Gallery會(huì)首先查找此文件,如果存在的話就會(huì)先使用它。
 *}
<div class="gbBlock gcBackground1">
  <h2> {g->text text="Look, it's my first page! And it's got a title."} </h2>
</div>

這將在頂部創(chuàng)建美觀的breadcrumb導(dǎo)航。注意G2系統(tǒng)呼叫在模板中的使用方式。如果你嘗試使用JavaScript,CSS或其他HTML相關(guān)的,使用大括號的古怪玩意的話,那么所有的Smarty呼叫都被包含在大括號內(nèi),有時(shí)會(huì)產(chǎn)生有趣的結(jié)果(當(dāng)然還有可怕的錯(cuò)誤)。如果你確實(shí)想這么做的話,請將你的代碼包括進(jìn){literal}..{/literal}標(biāo)簽中以告知Smarty你不想其被翻譯。

另外使用{g->text text="在此輸入你的文本"}來輸出文本也是個(gè)好作法,但這不是必須的。就個(gè)人而言,我建議你不這么做,因?yàn)檫@將有可能會(huì)使你的模塊被翻譯成其他語言。

現(xiàn)在來填寫模板的剩余部分。

<div class="gbBlock">
  <p class="giDescription">
    {g->text text="Hey, cool! I can write stuff here."}
  </p>
</div>

<div class="gbBlock">   
  <p class="giDescription">
    {g->text text="Look, when I do this G2 makes me a nice little divisor."}
    <br/>
    {if $MyPage.showAlbum}
      {$MyPage.album.title|markup}
    {/if}
  </p>
</div>

我希望此模板足以進(jìn)行自我解釋。正如前面提到的,大部分可以使用HTML解決的問題同樣可以使用模板引擎來完成。慢慢把玩此模板,直到達(dá)到你滿意的效果。該文件最高級的部分就是以{if開頭那行之上的一點(diǎn)點(diǎn)。這是Smarty使用的語法,從而能夠根據(jù)情況顯示輸出。由于我們在模板數(shù)據(jù)中將"showAlbum"設(shè)定為true,因此你應(yīng)當(dāng)能在頁面中看到根相冊的標(biāo)題。參見 Tpl相關(guān)參考中對Smarty功能的簡述。

頁面的訪問

我們還沒有在G2中對頁面做任何連接,那么該如何進(jìn)行訪問呢?走運(yùn)的是,G2(至少需要獨(dú)立版本的G2)具有的一個(gè)標(biāo)準(zhǔn)方法可以訪問模塊和它們的視圖:

http://www.example.com/main.php?g2_view=tutorial2.MyPage

你應(yīng)當(dāng)能看到新的靜態(tài)頁面被完美地包裹在G2外觀主題和CSS之中。如果你得到了某個(gè)訪問錯(cuò)誤檢查,你可以在'Site Admin / Plugins中激活該模塊。

帶有動(dòng)作的頁面

前言

Now that you can create a view to display something, let's add an action to that page.

模塊結(jié)構(gòu)

We'll build from your tutorial2 module for this one.

templates/MyPage.tpl

In this file you've already got

    {if $MyPage.showAlbum}
      {$MyPage.album.title|markup}
    {/if}

Let's add a form to perform an action.

    {if $MyPage.showAlbum}
      {if isset($status.saved)}
        <div class="giSuccess"> {g->text text="Saved!"} </div>
      {/if}
      {$MyPage.album.title|markup} <br/>
      <form method="POST" action="{g->url}">
        {g->hiddenFormVars}
        <input type="hidden" name="{g->formVar var="controller"}" value="tutorial2.MyPage"/>
        <input type="hidden" name="{g->formVar var="form[formName]"} value="{$form.formName}"/>
        <input type="text" size="2" name="{g->formVar var="form[char]"}" value="{$form.char}"/>
        {if isset($form.error.char)}
          <div class="giError"> {g->text text="Enter a single character"} </div>
        {/if}
        <input type="submit" class="inputTypeSubmit" name="{g->formVar var="form[action][addChar]"}"
         value="{g->text text="Add to title"}"/>
      </form>
    {/if}

This creates a form that will send data to a "controller" called tutorial2.MyPage. A view defines a page display, where a controller handles actions for that page. We define the controller also in MyPage.inc. The g->formVar calls add a prefix ("g2_") to the form fields. This helps avoid conflicts with other applications when G2 is embedded. You can see status messages above for success and error conditions. We'll explain how those are used below.

Note: If you get a ERROR_REQUEST_FORGED, you probably forgot to add {g->hiddenFormVars} to your <form> in the .tpl file.

MyPage.inc

We already have MyPageView defined. We'll need to add MyPageController, but first let's modify the view to initialize our form. Add the following after global $gallery; in function loadTemplate.

        if ($form['formName'] != 'MyPage') {
            $form['formName'] = 'MyPage';
            $form['char'] = '';
        }

When you first visit your view, $form is empty. So we initialize the form name and an empty value for "char".

Now to our controller. Add this definition just above the class MyPageView line.

class MyPageController extends GalleryController {

    /**
     * @see GalleryController::handleRequest
     */
    function handleRequest($form) {

The handleRequest function is called when an action is sent to the tutorial2.MyPage controller. All our form fields had names starting with "form[" so they have been loaded into the $form variable for us. Let's check the form input and perform the action.

        $status = $error = array();
        if (isset($form['action']['addChar'])) {
            if (strlen($form['char']) != 1) {
                $error[] = 'form[error][char]';
            } else {
                list ($ret, $albumId) = GalleryCoreApi::getDefaultAlbumId();
                if ($ret) {
                    return array($ret, null);
                }
                $ret = GalleryCoreApi::assertHasItemPermission($albumId, 'core.edit');
                if ($ret) {
                    return array($ret, null);
                }
                list ($ret, $lockId) = GalleryCoreApi::acquireWriteLock($albumId);
                if ($ret) {
                    return array($ret, null);
                }
                list ($ret, $album) = GalleryCoreApi::loadEntitiesById($albumId);
                if ($ret) {
                    GalleryCoreApi::releaseLocks($lockId);
                    return array($ret, null);
                }

                $album->setTitle($album->getTitle() . $form['char']);
                $ret = $album->save();
                if ($ret) {
                    GalleryCoreApi::releaseLocks($lockId);
                    return array($ret, null);
                }
                $ret = GalleryCoreApi::releaseLocks($lockId);
                if ($ret) {
                    return array($ret, null);
                }
                $status['saved'] = 1;
            }
        }

Several GalleryCoreApi calls here.. basically, if the requested action is "addChar" and a "char" value is given then we verify edit permission on the root album, lock it, load it, modify the title, save the change and release the lock. You can take a look at modules/core/classes/GalleryCoreApi.class or the apidoc to see the long list of things you can do with GalleryCoreApi.

If the "char" value was not a single character we set a value in $error. If the action went ok we set a value in $status. Look back at the tpl file to see where we check for these and show the appropriate message.

Next we need to tell G2 what to do now that our action is complete. We'll jump back to our view.

        $method = empty($error) ? 'redirect' : 'delegate';
        $result = array($method => array('view' => 'tutorial2.MyPage'),
                        'status' => $status, 'error' => $error);
        return array(null, $result);

On success we use a redirect back to our view and show the status message. On error we "delegate" back to our view. This means the $form data, even though not saved due to the error condition, is maintained so the user can fix the error and resubmit the form. Not a big deal in our form here with just one field, but this is handy if you filled in several things and just had an error in one.

Finally, close the handleRequest function and the controller class.

    }
}

測試

Login as a site admin (or other user with permission to edit the root album), browse to your view and try clicking the submit button with various inputs (too short, too long, just right). Click "reload" in your browser after a successful save to see that the status message appears only once.

模塊Callback

These are values you can add in the setCallbacks call in module.inc. Setting a callback means that when the value specified is called, the corresponding function in your module class will be polled.

Example: $this->setCallbacks('getSiteAdminViews|getItemLinks'); (value is a | separated list).

For each entry here, define the function with that name in your module class (apidoc).

  • getSiteAdminViews: Insert links in site administration
  • getItemAdminViews: Insert links for items administration
  • getUserAdminViews: Insert links for user administration
  • getItemLinks: Insert links for items (Edit Photo, Add Comment, etc)
  • getSystemLinks: Links not associated with a particular item (Login, Site Admin, etc)
  • getItemSummaries: Insert summary content about items
  • registerEventListeners: Listen for events to add advanced functionality

與數(shù)據(jù)庫的協(xié)作

In G2 most of the DB interaction is done through helper classes that are generated using a series of tools. This section will discuss the files that are needed, the tools that are needed and the procedures needed to get simple database operations working.

GNUmakefiles are not very important to understand, except that they are the method that all of the generated code is made. To run them you will need 'gmake' or 'make' and commandline PHP.

You will need the following GNUmakefile files. Copy them from another module (like comment) and make any directories that are needed. If our module were named dbExample, the directory structure would look like this:

dbExample/classes/GNUmakefile
dbExample/classes/GalleryStorage/GNUmakefile

There are two types of G2 tables:

  1. Entity tables.
    • Entity tables store objects like users, images or comments, and have a matching PHP file in the module's classes directory. As you might guess, an image would have different fields (path, name, description, etc.) than a comment (subject, commentorId, comment, etc.). Consequently, they are both entities even though their data reside in different tables.
  2. Map tables
    • Map tables contain any other data a module may need to store.

Entities are defined with a PHP class. See modules/comment/classes/GalleryComment.class as an example. Comments with @g2 tags define the database structure. Important parts of this file include:

  • Comment at the top with @g2 tags to define class-name, parent-class-name and version number for the table.
  • GalleryCoreApi::requireOnce call to load the parent class
  • class EntityName extends ParentClass
  • var definitions for each data field of the entity, each with a comment above it to define that field with @g2 tags.
  • The class must define get/set functions for all its data fields.

Maps are defined in classes/Maps.xml. See modules/customfield/classes/Maps.xml as an example. The structure of the table is defined in XML.

The DTDs for entity/map definitions are in lib/tools/dtd so you can see the available options for table/column definitions.

Once the entity and/or map definitions are ready, go to the command line, change into the classes directory and do make (or gmake). This will build the following files:

  • classes/GalleryStorage/schema.tpl and
  • classes/Maps.inc and/or
  • classes/Entities.inc

To use an entity you must register it (see function performFactoryRegistrations() in modules/comment/module.inc). You can then use GalleryCoreApi::newFactoryInstance to create an instance, $entity->create() to initialize it and $entity->save() to save it. GalleryCoreApi::loadEntitiesById loads entities.

Use these Core APIs to interact with maps:

  • GalleryCoreApi
addMapEntry
updateMapEntry
removeMapEntry
removeAllMapEntries

In Gallery 2.2+ you can use GalleryCoreApi::getMapEntry; prior to this you must use $gallery->search and provide a SQL query for your map. akes them much easier to edit.

Let's get started.

{*
 * $Revision$
 * 如果你想對此文件進(jìn)行自定義的話,請勿直接編輯它,因?yàn)樵趯砩墪r(shí)
 * 會(huì)將其覆蓋掉。請將其復(fù)制到一個(gè)名為"local"的新建文件夾中再進(jìn)行編輯
 * Gallery會(huì)首先查找此文件,如果存在的話就會(huì)先使用它。
 *}
<div class="gbBlock gcBackground1">
  <h2> {g->text text="Look, it's my first page! And it's got a title."} </h2>
</div>

這將在頂部創(chuàng)建美觀的breadcrumb導(dǎo)航。注意G2系統(tǒng)呼叫在模板中的使用方式。所有Smarty呼叫都被包含在大括號內(nèi),有時(shí)會(huì)產(chǎn)生有趣的結(jié)果(當(dāng)然還有可怕的錯(cuò)誤),如果你嘗試使用JavaScript,CSS或其他HTML相關(guān)使用大括號的古怪玩意的話。如果你確實(shí)想這么做的話,請將你的代碼包括進(jìn){literal}..{/literal}標(biāo)簽中以告知Smarty你不想其被翻譯。

另外使用{g->text text="在此輸入你的文本"}來輸出文本也是個(gè)好作法,但這不是必須的。就個(gè)人而言,我建議你不這么做,因?yàn)檫@將有可能會(huì)使你的模塊被翻譯成其他語言。

現(xiàn)在來填寫模板的剩余部分。

<div class="gbBlock">
  <p class="giDescription">
    {g->text text="Hey, cool! I can write stuff here."}
  </p>
</div>

<div class="gbBlock">   
  <p class="giDescription">
    {g->text text="Look, when I do this G2 makes me a nice little divisor."}
    <br/>
    {if $MyPage.showAlbum}
      {$MyPage.album.title|markup}
    {/if}
  </p>
</div>

我希望此模板足以進(jìn)行自我解釋。正如前面提到的,大部分可以使用HTML解決的問題同樣可以使用模板引擎來完成。慢慢把玩此模板,直到達(dá)到你滿意的效果。該文件最高級的部分就是以{if開頭那行之上的一點(diǎn)點(diǎn)。這是Smarty使用的語法,從而能夠根據(jù)情況顯示輸出。由于我們在模板數(shù)據(jù)中將"showAlbum"設(shè)定為true,因此你應(yīng)當(dāng)能在頁面中看到根相冊的標(biāo)題。參見 Tpl相關(guān)參考中對Smarty功能的簡述。

頁面的訪問

我們還沒有在G2中對頁面做任何連接,那么該如何進(jìn)行訪問呢?走運(yùn)的是,G2(至少需要獨(dú)立版本的G2)具有的一個(gè)標(biāo)準(zhǔn)方法可以訪問模塊和它們的視圖:

http://www.example.com/main.php?g2_view=tutorial2.MyPage

你應(yīng)當(dāng)能看到新的靜態(tài)頁面被完美地包裹在G2外觀主題和CSS之中。如果你得到了某個(gè)訪問錯(cuò)誤檢查,你可以在'Site Admin / Plugins中激活該模塊。

帶有動(dòng)作的頁面

前言

Now that you can create a view to display something, let's add an action to that page.

模塊結(jié)構(gòu)

We'll build from your tutorial2 module for this one.

templates/MyPage.tpl

In this file you've already got

    {if $MyPage.showAlbum}
      {$MyPage.album.title|markup}
    {/if}

Let's add a form to perform an action.

    {if $MyPage.showAlbum}
      {if isset($status.saved)}
        <div class="giSuccess"> {g->text text="Saved!"} </div>
      {/if}
      {$MyPage.album.title|markup} <br/>
      <form method="POST" action="{g->url}">
        {g->hiddenFormVars}
        <input type="hidden" name="{g->formVar var="controller"}" value="tutorial2.MyPage"/>
        <input type="hidden" name="{g->formVar var="form[formName]"} value="{$form.formName}"/>
        <input type="text" size="2" name="{g->formVar var="form[char]"}" value="{$form.char}"/>
        {if isset($form.error.char)}
          <div class="giError"> {g->text text="Enter a single character"} </div>
        {/if}
        <input type="submit" class="inputTypeSubmit" name="{g->formVar var="form[action][addChar]"}"
         value="{g->text text="Add to title"}"/>
      </form>
    {/if}

This creates a form that will send data to a "controller" called tutorial2.MyPage. A view defines a page display, where a controller handles actions for that page. We define the controller also in MyPage.inc. The g->formVar calls add a prefix ("g2_") to the form fields. This helps avoid conflicts with other applications when G2 is embedded. You can see status messages above for success and error conditions. We'll explain how those are used below.

Note: If you get a ERROR_REQUEST_FORGED, you probably forgot to add {g->hiddenFormVars} to your <form> in the .tpl file.

MyPage.inc

We already have MyPageView defined. We'll need to add MyPageController, but first let's modify the view to initialize our form. Add the following after global $gallery; in function loadTemplate.

        if ($form['formName'] != 'MyPage') {
            $form['formName'] = 'MyPage';
            $form['char'] = '';
        }

When you first visit your view, $form is empty. So we initialize the form name and an empty value for "char".

Now to our controller. Add this definition just above the class MyPageView line.

class MyPageController extends GalleryController {

    /**
     * @see GalleryController::handleRequest
     */
    function handleRequest($form) {

The handleRequest function is called when an action is sent to the tutorial2.MyPage controller. All our form fields had names starting with "form[" so they have been loaded into the $form variable for us. Let's check the form input and perform the action.

        $status = $error = array();
        if (isset($form['action']['addChar'])) {
            if (strlen($form['char']) != 1) {
                $error[] = 'form[error][char]';
            } else {
                list ($ret, $albumId) = GalleryCoreApi::getDefaultAlbumId();
                if ($ret) {
                    return array($ret, null);
                }
                $ret = GalleryCoreApi::assertHasItemPermission($albumId, 'core.edit');
                if ($ret) {
                    return array($ret, null);
                }
                list ($ret, $lockId) = GalleryCoreApi::acquireWriteLock($albumId);
                if ($ret) {
                    return array($ret, null);
                }
                list ($ret, $album) = GalleryCoreApi::loadEntitiesById($albumId);
                if ($ret) {
                    GalleryCoreApi::releaseLocks($lockId);
                    return array($ret, null);
                }

                $album->setTitle($album->getTitle() . $form['char']);
                $ret = $album->save();
                if ($ret) {
                    GalleryCoreApi::releaseLocks($lockId);
                    return array($ret, null);
                }
                $ret = GalleryCoreApi::releaseLocks($lockId);
                if ($ret) {
                    return array($ret, null);
                }
                $status['saved'] = 1;
            }
        }

Several GalleryCoreApi calls here.. basically, if the requested action is "addChar" and a "char" value is given then we verify edit permission on the root album, lock it, load it, modify the title, save the change and release the lock. You can take a look at modules/core/classes/GalleryCoreApi.class or the apidoc to see the long list of things you can do with GalleryCoreApi.

If the "char" value was not a single character we set a value in $error. If the action went ok we set a value in $status. Look back at the tpl file to see where we check for these and show the appropriate message.

Next we need to tell G2 what to do now that our action is complete. We'll jump back to our view.

        $method = empty($error) ? 'redirect' : 'delegate';
        $result = array($method => array('view' => 'tutorial2.MyPage'),
                        'status' => $status, 'error' => $error);
        return array(null, $result);

On success we use a redirect back to our view and show the status message. On error we "delegate" back to our view. This means the $form data, even though not saved due to the error condition, is maintained so the user can fix the error and resubmit the form. Not a big deal in our form here with just one field, but this is handy if you filled in several things and just had an error in one.

Finally, close the handleRequest function and the controller class.

    }
}

測試

Login as a site admin (or other user with permission to edit the root album), browse to your view and try clicking the submit button with various inputs (too short, too long, just right). Click "reload" in your browser after a successful save to see that the status message appears only once.

模塊Callback

These are values you can add in the setCallbacks call in module.inc. Setting a callback means that when the value specified is called, the corresponding function in your module class will be polled.

Example: $this->setCallbacks('getSiteAdminViews|getItemLinks'); (value is a | separated list).

For each entry here, define the function with that name in your module class (apidoc).

  • getSiteAdminViews: Insert links in site administration
  • getItemAdminViews: Insert links for items administration
  • getUserAdminViews: Insert links for user administration
  • getItemLinks: Insert links for items (Edit Photo, Add Comment, etc)
  • getSystemLinks: Links not associated with a particular item (Login, Site Admin, etc)
  • getItemSummaries: Insert summary content about items
  • registerEventListeners: Listen for events to add advanced functionality

與數(shù)據(jù)庫的協(xié)作

In G2 most of the DB interaction is done through helper classes that are generated using a series of tools. This section will discuss the files that are needed, the tools that are needed and the procedures needed to get simple database operations working.

GNUmakefiles are not very important to understand, except that they are the method that all of the generated code is made. To run them you will need 'gmake' or 'make' and commandline PHP.

You will need the following GNUmakefile files. Copy them from another module (like comment) and make any directories that are needed. If our module were named dbExample, the directory structure would look like this:

dbExample/classes/GNUmakefile
dbExample/classes/GalleryStorage/GNUmakefile

There are two types of G2 tables:

  1. Entity tables.
    • Entity tables store objects like users, images or comments, and have a matching PHP file in the module's classes directory. As you might guess, an image would have different fields (path, name, description, etc.) than a comment (subject, commentorId, comment, etc.). Consequently, they are both entities even though their data reside in different tables.
  2. Map tables
    • Map tables contain any other data a module may need to store.

Entities are defined with a PHP class. See modules/comment/classes/GalleryComment.class as an example. Comments with @g2 tags define the database structure. Important parts of this file include:

  • Comment at the top with @g2 tags to define class-name, parent-class-name and version number for the table.
  • GalleryCoreApi::requireOnce call to load the parent class
  • class EntityName extends ParentClass
  • var definitions for each data field of the entity, each with a comment above it to define that field with @g2 tags.
  • The class must define get/set functions for all its data fields.

Maps are defined in classes/Maps.xml. See modules/customfield/classes/Maps.xml as an example. The structure of the table is defined in XML.

The DTDs for entity/map definitions are in lib/tools/dtd so you can see the available options for table/column definitions.

Once the entity and/or map definitions are ready, go to the command line, change into the classes directory and do make (or gmake). This will build the following files:

  • classes/GalleryStorage/schema.tpl and
  • classes/Maps.inc and/or
  • classes/Entities.inc

To use an entity you must register it (see function performFactoryRegistrations() in modules/comment/module.inc). You can then use GalleryCoreApi::newFactoryInstance to create an instance, $entity->create() to initialize it and $entity->save() to save it. GalleryCoreApi::loadEntitiesById loads entities.

Use these Core APIs to interact with maps:

  • GalleryCoreApi
addMapEntry
updateMapEntry
removeMapEntry
removeAllMapEntries

In Gallery 2.2+ you can use GalleryCoreApi::getMapEntry; prior to this you must use $gallery->search and provide a SQL query for your map.