Gallery: 模块开发教程:修订间差异

来自站长百科
跳转至: 导航、​ 搜索
无编辑摘要
第1行: 第1行:
== General Notes ==
== 一般注释 ==
Parts taken with permission from: http://txtdump.com/g2dev/
部分内容经许可取自:http://txtdump.com/g2dev/


The code here has been updated for Gallery 2.2.
此处的代码针对Gallery2.2已经过更新。


=== Module Creator Script ===
=== 模块创建脚本(Module Creator Script) ===


This tutorial will guide you to create all module files from scratch.  You can also create the files for a new module by going to the command line and running <tt>php lib/tools/creator/create-module.php</tt> from your gallery2 directory.
该教程将帮助你从零开始创建所有的模块文件。你还可通过命令行运行gallery2目录的<tt>php lib/tools/creator/create-module.php</tt>来新建模块。
:'''Note:''' You must have a G2 developer package or install from svn/nightly snapshot to get lib/tools/creator.
:'''注:''' 你必须有G2开发者整合包或从svn/nightly snapshot进行安装以获得lib/tools/creator。


== Developing for G2: an Introduction ==
== G2开发:介绍 ==


=== Preface ===
=== 前言 ===
When first developing for G2 you can spend a lot of time trying to figure out the basics.  In this tutorial we will start with the basics, a module that somebody with no PHP experience whatsoever can code, and hope to move on to bigger and better things.
初次开发G2时,你可以尝试多花点时间来理解基本知识。此教程中我们会从最基本的开始,没用过PHP的人都可以学会编写模块代码,并且能做大做好。


=== The G2 Philosophy and Implementation ===
=== G2的“理”和“实”===


G2 has been developed to achieve almost complete separation of code and design as well as a pluggable module system. What does this mean to you? By using G2's [[Gallery:API|API]] (Application Programming Interface) you can add new functionality to G2 without modifying any of the core code.
G2几乎实现了代码和设计之间的完全分离,以及一套可插模块的系统。那么这对你意味着什么呢?通过使用G2的[[Gallery:API|API]](应用程序编程接口)你可以向G2添加新的功能而无需对核心代码做任何修改。


The first impulse I felt when I wanted to modify G2 was to find the code in question and edit it to fit my needs. While this is a very fast short-term solution, this sort of thinking would create major headaches in the future especially once you have to upgrade the core codebase. A much more efficient way to implement a modification or a new feature is to code a module for it. It may take you slightly more time to get started, but you will pat yourself on the back later when you realise that 'maintaining' your ten custom modules is as easy as changing a few lines to match with the new API versions.
在我想修改G2时的第一种冲动就是找到有问题的代码,然后将其修改为我需要的形式。但是这只是一个短期的权宜之计,在将来,尤其是你需要升级核心代码库时,麻烦就来了。实现某种修改或新特点的更有效途径就是编写模块。开始可能会多花费你一些时间,但之后你就会意识到维护好比10个模块,就如同修改几行语句以符合新版本的API那样轻松。


=== How Does G2 Work? ===
=== G2如何工作? ===


Before we get started, you need at least some understanding of how G2 works. For example, what happens when the user clicks the "Member List" link on the sidebar?
在开始之前,你至少需要明白G2的工作方式。比如,当点击边栏中的"成员列表(Member List)"链接是发生什么?


# The request goes to main.php, the main G2 wrapper script. It looks at the part of the URL appended to "main.php" that says "?g2_view=members.MembersList" and realizes that you want to load the "members" module and display the view, "MembersList" (a view is analogous to a dynamic G2 page).
# 请求送达main.php,即G2主要的包装脚本。它会看到后置到"main.php"的URL部分,"?g2_view=members.MembersList",然后获知你想载入"members"模块并显示视图"MembersList"(一个视图就是一个动态G2页面)。
# The "members" module is loaded, from modules/members and is told to display the "MembersList" view. The module loads up a file called MembersList.inc, which in turn uses the G2 API to contact the database and prepare all of the information required (membername, id, email, etc.).
# "members"模块从modules/members被载入,并被告知显示"MembersList"视图。模块载入一个名为MembersList.inc 的文件,它会使用G2 API来联系数据库并准备所有所需信息(membername,id,email等)。
# The default theme is loaded and instructed to display a module page.  You don't need to worry about this when coding a module, just be aware the theme can display stuff around your module content like a header/footer, etc.
# 默认外观主题被载入并被指示显示一个模块页面。在编写模块时你无需为此担忧,只要注意外观主题可以在你的模块内容周围显示东西即可,比如头/尾等。
# The corresponding template, modules/members/templates/MembersList.tpl, is loaded and the data is passed to it. The template generates a table with the data and the transaction is complete.
# 对应模板,modules/members/templates/MembersList.tpl,被载入而数据则被传送至此。该模板使用生成一个表格,事项处理就完成了。


As you can see, there are several distinct parts in the process, each of which serve their own purpose. With very few exceptions, you do not include complex code into the templates or templating data into the PHP code. Once you understand this key concept, developing for G2 becomes a whole lot easier.
如你所见,在此过程中有若干相异部分并各司其职。除了个别例外情况,不将复杂代码包括进模板,或将模板数据置入PHP代码中。一旦你理解此重要概念,G2的开发就变得更为简单了。


You've made it this far. Great! Let's continue on to creating a module for G2. It will be easy, I promise.
你已经看了这么多啦!真不简单!接下来我们来为G2创建模块。我打包票,绝对不难。


== Module Directory Structure ==
== 模块目录结构 ==


<tt>modules/$modulename/module.inc</tt>
<tt>modules/$modulename/module.inc</tt>
:: This is the entry point to every module. It defines what the module is and will do.  This is the only file every module must have. The rest may or may not be used depending on what the module does.
:: 此为各模块所具有的入口点。它定义模块的身份以及职能。此为所有模块所必须具有的文件,当然也是唯一必须的文件。其余文件则根据模块职能不同而有所取舍。
<tt>modules/$modulename/$viewname.inc</tt>
<tt>modules/$modulename/$viewname.inc</tt>
:: Pages are called "views". Each view is given its own .inc file. The name of the file is the same as the view. If the view can perform any actions (i.e., it has buttons that do something) then this file will also have a "controller" class which handles those actions.
:: 页面被称为"视图(view)"。各视图都具有各自的.inc文件。该文件的文件名与视图相同。如果视图可以执行任何动作的话(即可通过按钮完成一些行为),那么该文件还会具有一个"控制器(controller)"类别,用以处理这些动作。
<tt>modules/$modulename/templates/$viewname.tpl</tt>
<tt>modules/$modulename/templates/$viewname.tpl</tt>
:: The actual HTML for each view is in a template file with the same name as the view.
:: 各视图的实际HTML位于一个模板文件中,该文件具有与视图相同的文件名。
<tt>modules/$modulename/templates/blocks/blocks.inc</tt>
<tt>modules/$modulename/templates/blocks/blocks.inc</tt>
:: A PHP file that tells each theme what blocks are available and what template file to load for each one. This file is not required for blocks to function, but it makes them available for themes to use in settings for "sidebar blocks", "photo blocks", etc.
:: 此为一PHP文件,它告知各外观主题哪些为可用区块以及针对各区块所需载入的模板文件。该文件并非区块运行所必需的,但能使得这些区块可被外观主题用于"边栏区块(sidebar blocks)""相片区块(photo blocks)"等的设定之中。
<tt>modules/$modulename/templates/blocks/*.tpl</tt>
<tt>modules/$modulename/templates/blocks/*.tpl</tt>
:: Contains the template code for blocks specified from blocks.inc.
:: 包含自blocks.inc 所定义区块的模板代码。
<tt>modules/$modulename/Callbacks.inc</tt>
<tt>modules/$modulename/Callbacks.inc</tt>
:: This file is where callbacks are loaded from for each module.  A module that defines blocks may use this file to load data for the blocks.
:: 该文件为各模块callback加载所用。定义区块的模块可使用此文件加载区块数据。
<tt>modules/$modulename/Preloads.inc</tt>
<tt>modules/$modulename/Preloads.inc</tt>
:: This file is where preloads are loaded from for each module.  A module that defines blocks may use this file to specify css or javascript needed for the blocks.
:: 该文件为各模块preload加载所用。定义区块的模块可使用此文件指定区块所需的css或javascript。
<tt>modules/$modulename/classes/*Helper.class</tt>
<tt>modules/$modulename/classes/*Helper.class</tt>
:: *Helper.class files are optional. They are used to organize the code for things that are used in more than one view or simply to break up large code into manageable chunks.
:: *Helper.class文件为可选的。它们被用来组织用于多个视图内容的代码,或是将大块代码分解成易于管理的小块。
<tt>modules/$modulename/classes/*Interface.class</tt>
<tt>modules/$modulename/classes/*Interface.class</tt>
:: Interfaces are a way for multiple modules to share a common method for doing similar tasks. For example, the Search module implements a search interface that other modules build off of to add search capabilities to their module.
:: 接口针对多个模块共享某种常见方法以完成相似任务之用。比如,Search模块实现的search接口,其他模块可添加搜索(search)功能。
<tt>modules/$modulename/classes/Maps.xml</tt>
<tt>modules/$modulename/classes/Maps.xml</tt>
:: Database table schemes are stored in an XML file for portability. Gallery does the work to make it compatible with various database engines. This is needed only if the module stores data in the database.
:: 数据库表方案被保存在XML文件中以保证其可移植性。Gallery则会让它与各类数据库引擎兼容协作。仅当模块在数据库中保存数据的情况下才会用到它。
<tt>modules/$modulename/test/phpunit/*Test.class</tt>
<tt>modules/$modulename/test/phpunit/*Test.class</tt>
:: These are unit tests for a module. Visit <tt>lib/tools/phpunit/index.php</tt> in a Gallery install to run unit tests. These are automated tests to verify the module works as expected. They take time to write, but are very valuable to ensure Gallery core changes or your own module changes won't break the module.
:: 这些是模块的单元测试。访问Gallery中的<tt>lib/tools/phpunit/index.php</tt>来运行单元测试。这些自动化的测试旨在确认模块能按预期运行。它们的编写需要花费时间,但能保证Gallery核心更改或你自己对模块作出的修改不会对模块造成破坏。
<tt>modules/$modulename/po/*.po</tt>
<tt>modules/$modulename/po/*.po</tt>
:: These are [[Gallery:Localization|translations]] of text in your module to other languages.
:: 这些是模块中文本在其他语言中的[[Gallery:Localization|翻译]]
<tt>modules/$modulename/locale/*</tt>
<tt>modules/$modulename/locale/*</tt>
:: These are the compiled translations actually used by Gallery.
:: 这些为Gallery实际所使用的经编译的翻译。


== Coding a Dummy Module ==
== 哑模块编码 ==


=== Preface ===
=== 前言 ===


Now that you have a basic grasp of the G2 system, let's dive in and code a basic module.
现在你应该基本了解了G2系统,那么我们就开始深入下去吧,比如编写一个基础模块。


:'''Note:''' Make sure that PHP shows you syntax errors and other problems. See: [[Gallery:Developer_Guidelines#PHP_Settings|PHP Settings for Gallery developers]], especially the note about ''display_errors' in your ''gallery2/config.php''.
:'''注:''' 确保PHP能显示语法错误和其他问题。参见:[[Gallery:Developer_Guidelines#PHP_Settings|针对Gallery开发者的PHP设定]],尤其注意一下''gallery2/config.php''中的''display_errors''。


=== Module Structure ===
=== 模块结构 ===


All modules in G2 must have their own directory (folder) under ''modules/'' as well as a ''module.inc'' file within that directory. Go ahead and create both using your preferred method. Name the directory ''tutorial1''.
G2中的所有模块在''modules/''目录下都必须具有自己的目录,并在该目录下含有一个''module.inc''文件。用你习惯的方法创建它们。将目录命名为''tutorial1''


Tip: in *nix systems, the <tt>touch</tt> command is useful for creating empty files.
提示:在*nix系统中。<tt>touch</tt>命令可用来创建空文件。


Great! You now have the following:
就是这样!现在你就有这些了:
<pre>
<pre>
modules/tutorial1/          (directory)
modules/tutorial1/          (目录)
modules/tutorial1/module.inc (empty file)
modules/tutorial1/module.inc (空文件)
</pre>
</pre>


====''module.inc''====
====''module.inc''====


''module.inc'' is the very 'core' of your module. It tells G2 things like the module's name, description, and version, as well as a whole myriad of other nifty stuff.  So let's fill it in.
''module.inc''是模块最'核心'的部分。它告知G2诸如模块名称,描述及版本一类的信息,以及其他庞杂的细枝末节。.


First, we tell the world that this is a PHP script. Easy enough, just start with:
首先我们表明此为一PHP脚本。很简单,如此开头即可:


<pre>
<pre>
第92行: 第92行:
</pre>
</pre>


Now, let's paste in the standard G2 boilerplate.
现在,将其粘贴到G2标准样版文件中。


<pre>
<pre>
/*
/*
  * Gallery - a web based photo album viewer and editor
  * Gallery – 基于web的相片相册查看器和编辑器
  * Copyright (C) 2000-2006 Bharat Mediratta
  * Copyright (C) 2000-2006 Bharat Mediratta
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 该程序为免费的,你可以对其做修改
  * it under the terms of the GNU General Public License as published by
  * 受GNU General Public License条款约束
  * the Free Software Foundation; either version 2 of the License, or (at
  * 由Free Software Foundation发布;许可的第二版,或者说是
  * your option) any later version.
  * 以后的版本。
  *
  *
  * This program is distributed in the hope that it will be useful, but
  * 我们希望该应用程序能有用处,但
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * 不打包票;也不能保证其
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * 适销性或针对特殊目的的适用性。更多信息请参见GNU
  * General Public License for more details.
  * General Public License。
  *
  *
  * You should have received a copy of the GNU General Public License
  * 在获取此程序的同时,你应当也收到了
* along with this program; if not, write to the Free Software
* GNU General Public License;如果没有的话,请联系Free Software
  * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
  * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
  */
  */
</pre>
</pre>


Then, we want to fill in some administrative data. You don't have to change any of this. This data is not used by our module for anything, but G2 uses it for management/documentation purposes.
接下来我们要填入一些管理数据。你不需要进行任何修改。该数据不会为模块所用,但G2会将其用于管理/文档处理。


<pre>
<pre>
第129行: 第129行:
</pre>
</pre>


Next, we tell G2 that our tutorial1 module is extending ''GalleryModule''.
接下来,我们告知G2我们的tutorial1模块将扩展''GalleryModule''


<pre>
<pre>
第135行: 第135行:
</pre>
</pre>


Now we need to fill in the required data for the module. We do this in the module's ''Tutorial1Module'' function.
现在我们需要填入该模块所需的数据。这将在模块的''Tutorial1Module''函数中完成。


<pre>
<pre>
第152行: 第152行:
</pre>
</pre>


The first three fields above are fairly self-descriptive. The ''setId'' value must match the directory name for your module. The ''$gallery->i18n'' line allows text fields to be translated into other languages. The ''setVersion'' parameter is simply a version number you want to use for your module. We'll use 0.9.0 to start. ''setGroup'' refers to the group the module will be placed under the the Site Admin pages. We don't need to set any callbacks just yet, so we leave that blank.
前三行是自描述的。''setId''值必须符合模块的目录名。''$gallery->i18n''行允许文本字段被翻译成其他语言。''setVersion''字段则只是用于模块的版本号,我们使用0.9.0。''setGroup''指的是站点管理页面中模块将被放入的组。我们还不需要设定callback,因此这里先空着不管。


Our ''RequiredCoreApi'' and ''RequiredModuleApi'' versions must match G2's provided versions, or things will break. Want to know your G2's latest API version? Check one of the G2 Team's modules in your install and use the numbers from there. Here, we're using the CoreAPI v 7.10 and ModuleAPI v 3.2.
我们的''RequiredCoreApi''''RequiredModuleApi''版本必须符合G2所提供的版本,不然的话就会造成破坏。你想知道G2最新的API版本?检查G2 Team的某个模块并使用它的版本号。这里我们会使用CoreAPI v 7.10和ModuleAPI v 3.2。


'''Note:''' Gallery 2.3 modules will have an additional line in the constructor:
'''注:''' Gallery 2.3模块会在构建式里多出一行:
<pre>
<pre>
         $this->_templateVersion = 1;
         $this->_templateVersion = 1;
</pre>
</pre>
:Gallery 2.3 themes can override module tpl files. Increment this number whenever releasing a new version of the module that includes changes in any tpl file that are incompatible with previous versions. Theme overrides will only be used when the template version matches. Note that this code in the module constructor does not use $this->setTemplateVersion(1) in case someone installs the module on Gallery 2.2.x or older where this method does not exist. A PHP error in the module constructor would prevent Gallery's API version checking.
:Gallery 2.3的外观主题可以覆盖模块的tpl文件。当模块新版本发布时请注意增加此数字,因为其在tpl文件中的修改无法与旧版本兼容。外观主题覆盖仅当模板版本相符时才能使用。注意,如果某人安装了Gallery2.2.x或更早版本的模块,而此方法不存在时,模块构建式中的此代码就不会使用$this->setTemplateVersion(1)。模块构建式中的PHP错误将会妨碍Gallery API的版本检查。


We're done! Let's close it up with:
完成了,使用如下内容做结束:


<pre>
<pre>
第169行: 第169行:
</pre>
</pre>


The entire ''module.inc'' code is [[Tutorial module.inc Code|available here]].
整个''module.inc''代码[[Tutorial module.inc Code|可在此找到]]


=== Installing/Activating your Module ===
=== 模块的安装和激活 ===


Congratulations! You've now coded your first G2 module! But so far, your module does not do anything. It's hard to use something with no functionality, but provided everything went smoothly you'll be able to login to your Site Admin interface, click ''Plugins'', scroll down to the ''Extra Data'' section, and then install and activate (and deactivate and uninstall) your module. Fun, isn't it?
祝贺你,你已经编写完成了第一个G2模块!但目前你的模块还无法实际使用。如果不启用功能的话,就没有任何用处;所以,如果没有问题的话,你可以登入站点管理界面,点击''插件(Plugins)'',下拉到''额外数据(Extra Data)''部分,然后安装并激活(在此还可以进行禁用和卸载)你的模块。很有意思,是不?


You've just created a fully compatible, standards-compliant, wonderful, amazing, brilliant module for G2.  You'll find that all of your future modules will follow the same structure.  Give yourself a pat on the back and continue to the next section where you'll learn to create a module that starts using the templating engine.
你刚刚创建完成了一个完全兼容且完美的G2模块。你会发现将来所制作的模块结构都是如此。好吧,是时候鼓励一下自己了,接下来的部分将教会你创建使用模板引擎的模块。


== A Module that Displays Static Pages ==
== 显示静态页面的模块 ==


=== Preface ===  
=== 前言 ===  


Now that you know how to create a proper G2 module let's go one step further and create a module that uses the G2 templating engine to show static pages.
现在你知道如何创建一个G2模块了,那么就让我们更深一步,创建使用模板引擎的模块以显示静态页面。


=== Module Structure ===  
=== 模块结构 ===  


To begin, create a <tt>modules/tutorial2</tt> directory. We'll continue on where you left off with the last module. Copy the old ''module.inc'' into the new directory but make sure to change all instances of ''tutorial1'' to ''tutorial2'' and ''Tutorial1'' to ''Tutorial2''.
首先创建一个<tt>modules/tutorial2</tt>目录。我们将从之前的模块继续。将旧的''module.inc''复制到新目录中,但请确保将''tutorial1''的所有实例修改为''tutorial2''''Tutorial1''修改为''Tutorial2''


Also, let's create the following files and directories. You can leave the files empty for now.
另外,创建如下的文件和目录,目前这些文件都可以为空。


<pre>
<pre>
第197行: 第197行:
====''module.inc''====
====''module.inc''====


Great news, we don't need to make any changes to ''module.inc''! Just the existence of the ''MyPage.inc'' file allows G2 to use it. Let's continue and open the ''MyPage.inc'' file.
我们不需要对''module.inc''做任何修改。''MyPage.inc''文件存在就允许G2使用它。继续并打开''MyPage.inc''文件。


====''MyPage.inc''====
====''MyPage.inc''====


In G2, it is not possible to access templates directly. Rather, you must use a "view" that will prepare all the necessary data and then load the template itself. ''MyPage.inc'' is such a view.
在G2中是无法直接访问模板的。你必须使用一个"视图(view)",它将会准备所有必须的数据然后载入模板。''MyPage.inc''就是这样一种视图。


Let's start by pasting the regular G2 boilerplate.
现在开始粘贴一般的G2样板文件。


<pre>
<pre>
<?php
<?php
/*
/*
* Gallery - a web based photo album viewer and editor
* Gallery – 基于web的相片相册查看器和编辑器
  * Copyright (C) 2000-2006 Bharat Mediratta
  * Copyright (C) 2000-2006 Bharat Mediratta
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 该程序为免费的,你可以对其做修改
  * it under the terms of the GNU General Public License as published by
  * 受GNU General Public License条款约束
  * the Free Software Foundation; either version 2 of the License, or (at
  * 由Free Software Foundation发布;许可的第二版,或者说是
  * your option) any later version.
  * 以后的版本。
  *
  *
  * This program is distributed in the hope that it will be useful, but
  * 我们希望该应用程序能有用处,但
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * 不打包票;也不能保证其
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * 适销性或针对特殊目的的适用性。更多信息请参见GNU
  * General Public License for more details.
  * General Public License。
  *
  *
  * You should have received a copy of the GNU General Public License
  * 在获取此程序的同时,你应当也收到了
* along with this program; if not, write to the Free Software
* GNU General Public License;如果没有的话,请联系Free Software
  * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
  * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
  */
  */
</pre>
</pre>


Fill in the other standard data.
填入其他标准数据。


<pre>
<pre>
/**
/**
  * This view shows a static page.
  * 该视图显示一个静态页面。
  *
  *
  * @package Tutorial2
  * @package Tutorial2
第240行: 第240行:
</pre>
</pre>


Phew! The structure from ''module.inc'' may seem familiar to you so you might be able to guess what's coming. We want to extend the <tt>GalleryView</tt> class with your own class.
你应该对''module.inc''的结构不陌生吧,那你就应该知道接下来要做的了。我们希望使用你自己的类别对<tt>GalleryView</tt>类别进扩展。


<pre>
<pre>
第246行: 第246行:
</pre>
</pre>


The class name must match the name of your ''*.inc'' file with "View" added on the end. Now, our module doesn't have to do any data manipulation so we only need two functions. The main one is <tt>loadTemplate</tt>.
类别名称必须与你的''*.inc''文件名称相同,并以"View"结尾。现在,我们的模块还不需要做任何数据操作,我们只需要2个函数。其中主要的一个就是<tt>loadTemplate</tt>


<pre>
<pre>
第256行: 第256行:
</pre>
</pre>


In ''loadTemplate'' function we tell G2 everything we want to do before loading our template.
''loadTemplate''函数中,我们告知G2在载入模板前所需做的所有事情。


For our page, we'll load the top album of the Gallery so we can display some information about it.
对于我们的页面,将载入Gallery顶层相册,所以我们就可以显示有关它的一些信息了。


<pre>
<pre>
第272行: 第272行:
</pre>
</pre>


: '''Note:''' in Gallery 2.1.x <tt>return array($ret, null);</tt> would be <tt>return array($ret->wrap(__FILE__, __LINE__), null);</tt>
: '''注:''' 在Gallery 2.1.x中,<tt>return array($ret, null);</tt>应为<tt>return array($ret->wrap(__FILE__, __LINE__), null);</tt>


Take note of the structure of these calls, as it is fairly important. It is repeated throughout a lot of the G2 code. Also note that we've loaded the root album, but have not done anything with it just yet. Let's make that data available to our template.
将这些呼叫的结构记录下来,这相当重要,因为在很多G2代码中都要重复使用它。另外注意我们已加载了根相册,但还没有对其做任何操作。现在将这些数据用于我们的模板。


<pre>
<pre>
第281行: 第281行:
</pre>
</pre>


Any data we need to display our page should be given to <tt>$template->setVariable</tt>. Whenever an "entity" is added to the template data it should be converted to an array as shown above.
我们用以显示页面的数据应当被给予<tt>$template->setVariable</tt>。无论何时模板数据被添加一个"实体",它都应当被转换为上面所示的数组。


Let's continue by loading the template.
现在让我们继续,来加载模板。


<pre>
<pre>
第291行: 第291行:
</pre>
</pre>


If we've gone this far, the operation has been a success. Therefore, we tell G2 that we've succeeded and load the appropriate template file.
如果我们能走到这一步,那么所作的这些都成功了。所以,我们告知G2成功了,并载入合适的模板文件。


Ever notice those nice ''back to ____'' navigation links on the sidebar? Let's incorporate this feature into our module. We do this by creating another function.
你是否边栏上的注意到''back to ____''导航链接了?让我们将此特点整入我们的模块中吧。要达到此目的,我们要创建另一个函数。


<pre>
<pre>
第309行: 第309行:
</pre>
</pre>


Feel free to change "My Page" to whatever your heart desires. Finally, we close the class and the PHP script.
你可以将"My Page"改为你中意的明朝。最后,我们结束该类别以及PHP脚本。


<pre>
<pre>
第316行: 第316行:
</pre>
</pre>


Phew! While it looks like a lot of code for such a simple task, most of the code can be reused over and over in your subsequent modules. You'll find that once you know how to code a basic module you can simply keep building on your existing knowledge to easily code bigger and bigger modules.
这么简单的一个任务看起来却用到了这么多代码,但这些代码可以在你今后的模块编写中反复使用的。你会发现,一旦掌握了基本模块的编码手段,就能轻松如意地编写更大更丰富的模块了。


Let's continue with our last file, the template.
现在是最后一个文件了,模板。


====''templates/MyPage.tpl''====
====''templates/MyPage.tpl''====


As you should remember, the last call in the <tt>loadTemplate()</tt> function is the loading of the template. G2 uses the Smarty templating engine which provides excellent code and design separation. You'll find that you can use standard HTML in the template files, which makes them much easier to edit.
你应该能记得,<tt>loadTemplate()</tt>函数中的最后一个呼叫是模板的加载。G2使用Smarty模板引擎,这能提供很棒的代码与设计间的分离。 You'll find that you can use standard HTML in the template files, which makes them much easier to edit.


Let's get started.
Let's get started.
第329行: 第329行:
{*
{*
  * $Revision$
  * $Revision$
  * If you want to customize this file, do not edit it directly since future upgrades
  * 如果你想对此文件进行自定义的话,请勿直接编辑它,因为在将来升级时
  * may overwrite it.  Instead, copy it into a new directory called "local" and edit that
  * 会将其覆盖掉。请将其复制到一个名为"local"的新建文件夹中再进行编辑
  * version.  Gallery will look for that file first and use it if it exists.
  * Gallery会首先查找此文件,如果存在的话就会先使用它。
  *}
  *}
<div class="gbBlock gcBackground1">
<div class="gbBlock gcBackground1">
第338行: 第338行:
</pre>
</pre>


This creates the nice breadcrumb navigation at the top. Note how G2 system calls are still used in the templates, but not extensively. All Smarty calls are enveloped in the curly brackets which sometimes results in funny results (and horrible errors) if you try to use JavaScript, CSS, or any other HTML-related oddity that uses curly brackets. If you want to do so, just wrap your code with <tt>{literal}..{/literal}</tt> tags to tell Smarty that you don't want it to interpret it.
这将在顶部创建美观的breadcrumb导航。注意G2系统呼叫在模板中的使用方式。所有Smarty呼叫都被包含在大括号内,有时会产生有趣的结果(当然还有可怕的错误),如果你尝试使用JavaScript,CSS或其他HTML相关使用大括号的古怪玩意的话。如果你确实想这么做的话,请将你的代码包括进<tt>{literal}..{/literal}</tt>标签中以告知Smarty你不想其被翻译。


It is also good form to use <tt>{g->text text="your text here"}</tt> to output text, but this is not required. Personally, I recommend you do it regardless as it makes it possible to translate your module into other languages.
另外使用<tt>{g->text text="在此输入你的文本"}</tt>来输出文本也是个好作法,但这不是必须的。就个人而言,我建议你不这么做,因为这将有可能会使你的模块被翻译成其他语言。


Let's fill in the rest of the template.
现在来填写模板的剩余部分。


<pre>
<pre>
第362行: 第362行:
</pre>
</pre>


I hope that the template is fairly self explanatory. As mentioned earlier, most of the things you can do with HTML you can also achieve with the templating engine. Play around with the template until you think you have it looking the way you want it. The most advanced portion of this file is the bit above starting with <tt>{if</tt>. This is Smarty syntax to conditionally display some output. Since we set "showAlbum" to true in our template data, you should see the title of your root album in the page. See the [[Gallery:Tpl Reference|Tpl reference]] for the compendium of what you can do with Smarty.
我希望此模板足以进行自我解释。正如前面提到的,大部分可以使用HTML解决的问题同样可以使用模板引擎来完成。慢慢把玩此模板,直到达到你满意的效果。该文件最高级的部分就是以<tt>{if</tt>开头那行之上的一点点。这是Smarty使用的语法,从而能够根据情况显示输出。由于我们在模板数据中将"showAlbum"设定为true,因此你应当能在页面中看到根相册的标题。参见 [[Gallery:Tpl Reference|Tpl相关参考]]中对Smarty功能的简述。


=== Accessing your Page ===
=== 页面的访问 ===


We have not made any links in G2 to our page, so how do we access it? Luckily, G2 (the standalone version, at least) has a standard method of accessing modules and their views:
我们还没有在G2中对页面做任何连接,那么该如何进行访问呢?走运的是,G2(至少需要独立版本的G2)具有的一个标准方法可以访问模块和它们的视图:


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


You should be able to see your new static page wrapped nicely with the G2 theme and CSS. If you get an access error check you activated the module in ''Site Admin / Plugins''.
你应当能看到新的静态页面被完美地包裹在G2外观主题和CSS之中。如果你得到了某个访问错误检查,你可以在'Site Admin / Plugins''中激活该模块。


== A Page with Actions ==
== 带有动作的页面 ==


=== Preface ===
=== 前言 ===


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


=== Module Structure ===
=== 模块结构 ===


We'll build from your tutorial2 module for this one.
We'll build from your tutorial2 module for this one.
第505行: 第505行:
</pre>
</pre>


=== Test it out ===
=== 测试 ===


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.
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.


== Module Callbacks ==
== 模块Callback ==


These are values you can add in the <tt>setCallbacks</tt> 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.  
These are values you can add in the <tt>setCallbacks</tt> 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.  
第525行: 第525行:
* '''registerEventListeners''': Listen for events to add advanced functionality
* '''registerEventListeners''': Listen for events to add advanced functionality


== Working With the Database ==
== 与数据库的协作 ==


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.
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.
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.

2008年11月27日 (四) 17:11的版本

一般注释

部分内容经许可取自:http://txtdump.com/g2dev/

此处的代码针对Gallery2.2已经过更新。

模块创建脚本(Module Creator Script)

该教程将帮助你从零开始创建所有的模块文件。你还可通过命令行运行gallery2目录的php lib/tools/creator/create-module.php来新建模块。

注: 你必须有G2开发者整合包或从svn/nightly snapshot进行安装以获得lib/tools/creator。

G2开发:介绍

前言

初次开发G2时,你可以尝试多花点时间来理解基本知识。此教程中我们会从最基本的开始,没用过PHP的人都可以学会编写模块代码,并且能做大做好。

G2的“理”和“实”

G2几乎实现了代码和设计之间的完全分离,以及一套可插模块的系统。那么这对你意味着什么呢?通过使用G2的API(应用程序编程接口)你可以向G2添加新的功能而无需对核心代码做任何修改。

在我想修改G2时的第一种冲动就是找到有问题的代码,然后将其修改为我需要的形式。但是这只是一个短期的权宜之计,在将来,尤其是你需要升级核心代码库时,麻烦就来了。实现某种修改或新特点的更有效途径就是编写模块。开始可能会多花费你一些时间,但之后你就会意识到维护好比10个模块,就如同修改几行语句以符合新版本的API那样轻松。

G2如何工作?

在开始之前,你至少需要明白G2的工作方式。比如,当点击边栏中的"成员列表(Member List)"链接是发生什么?

  1. 请求送达main.php,即G2主要的包装脚本。它会看到后置到"main.php"的URL部分,"?g2_view=members.MembersList",然后获知你想载入"members"模块并显示视图"MembersList"(一个视图就是一个动态G2页面)。
  2. "members"模块从modules/members被载入,并被告知显示"MembersList"视图。模块载入一个名为MembersList.inc 的文件,它会使用G2 API来联系数据库并准备所有所需信息(membername,id,email等)。
  3. 默认外观主题被载入并被指示显示一个模块页面。在编写模块时你无需为此担忧,只要注意外观主题可以在你的模块内容周围显示东西即可,比如头/尾等。
  4. 对应模板,modules/members/templates/MembersList.tpl,被载入而数据则被传送至此。该模板使用生成一个表格,事项处理就完成了。

如你所见,在此过程中有若干相异部分并各司其职。除了个别例外情况,不将复杂代码包括进模板,或将模板数据置入PHP代码中。一旦你理解此重要概念,G2的开发就变得更为简单了。

你已经看了这么多啦!真不简单!接下来我们来为G2创建模块。我打包票,绝对不难。

模块目录结构

modules/$modulename/module.inc

此为各模块所具有的入口点。它定义模块的身份以及职能。此为所有模块所必须具有的文件,当然也是唯一必须的文件。其余文件则根据模块职能不同而有所取舍。

modules/$modulename/$viewname.inc

页面被称为"视图(view)"。各视图都具有各自的.inc文件。该文件的文件名与视图相同。如果视图可以执行任何动作的话(即可通过按钮完成一些行为),那么该文件还会具有一个"控制器(controller)"类别,用以处理这些动作。

modules/$modulename/templates/$viewname.tpl

各视图的实际HTML位于一个模板文件中,该文件具有与视图相同的文件名。

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

此为一PHP文件,它告知各外观主题哪些为可用区块以及针对各区块所需载入的模板文件。该文件并非区块运行所必需的,但能使得这些区块可被外观主题用于"边栏区块(sidebar blocks)"及"相片区块(photo blocks)"等的设定之中。

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

包含自blocks.inc 所定义区块的模板代码。

modules/$modulename/Callbacks.inc

该文件为各模块callback加载所用。定义区块的模块可使用此文件加载区块数据。

modules/$modulename/Preloads.inc

该文件为各模块preload加载所用。定义区块的模块可使用此文件指定区块所需的css或javascript。

modules/$modulename/classes/*Helper.class

*Helper.class文件为可选的。它们被用来组织用于多个视图内容的代码,或是将大块代码分解成易于管理的小块。

modules/$modulename/classes/*Interface.class

接口针对多个模块共享某种常见方法以完成相似任务之用。比如,Search模块实现的search接口,其他模块可添加搜索(search)功能。

modules/$modulename/classes/Maps.xml

数据库表方案被保存在XML文件中以保证其可移植性。Gallery则会让它与各类数据库引擎兼容协作。仅当模块在数据库中保存数据的情况下才会用到它。

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

这些是模块的单元测试。访问Gallery中的lib/tools/phpunit/index.php来运行单元测试。这些自动化的测试旨在确认模块能按预期运行。它们的编写需要花费时间,但能保证Gallery核心更改或你自己对模块作出的修改不会对模块造成破坏。

modules/$modulename/po/*.po

这些是模块中文本在其他语言中的翻译

modules/$modulename/locale/*

这些为Gallery实际所使用的经编译的翻译。

哑模块编码

前言

现在你应该基本了解了G2系统,那么我们就开始深入下去吧,比如编写一个基础模块。

注: 确保PHP能显示语法错误和其他问题。参见:针对Gallery开发者的PHP设定,尤其注意一下gallery2/config.php中的display_errors

模块结构

G2中的所有模块在modules/目录下都必须具有自己的目录,并在该目录下含有一个module.inc文件。用你习惯的方法创建它们。将目录命名为tutorial1

提示:在*nix系统中。touch命令可用来创建空文件。

就是这样!现在你就有这些了:

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

module.inc

module.inc是模块最'核心'的部分。它告知G2诸如模块名称,描述及版本一类的信息,以及其他庞杂的细枝末节。.

首先我们表明此为一PHP脚本。很简单,如此开头即可:

<?php

现在,将其粘贴到G2标准样版文件中。

/*
 * Gallery – 基于web的相片相册查看器和编辑器
 * Copyright (C) 2000-2006 Bharat Mediratta
 *
 * 该程序为免费的,你可以对其做修改
 * 受GNU General Public License条款约束
 * 由Free Software Foundation发布;许可的第二版,或者说是
 * 以后的版本。
 *
 * 我们希望该应用程序能有用处,但
 * 不打包票;也不能保证其
 * 适销性或针对特殊目的的适用性。更多信息请参见GNU
 * General Public License。
 *
 * 在获取此程序的同时,你应当也收到了
* GNU General Public License;如果没有的话,请联系Free Software
 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
 */

接下来我们要填入一些管理数据。你不需要进行任何修改。该数据不会为模块所用,但G2会将其用于管理/文档处理。

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

接下来,我们告知G2我们的tutorial1模块将扩展GalleryModule

class Tutorial1Module extends GalleryModule {

现在我们需要填入该模块所需的数据。这将在模块的Tutorial1Module函数中完成。

    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指的是站点管理页面中模块将被放入的组。我们还不需要设定callback,因此这里先空着不管。

我们的RequiredCoreApiRequiredModuleApi版本必须符合G2所提供的版本,不然的话就会造成破坏。你想知道G2最新的API版本?检查G2 Team的某个模块并使用它的版本号。这里我们会使用CoreAPI v 7.10和ModuleAPI v 3.2。

注: Gallery 2.3模块会在构建式里多出一行:

        $this->_templateVersion = 1;
Gallery 2.3的外观主题可以覆盖模块的tpl文件。当模块新版本发布时请注意增加此数字,因为其在tpl文件中的修改无法与旧版本兼容。外观主题覆盖仅当模板版本相符时才能使用。注意,如果某人安装了Gallery2.2.x或更早版本的模块,而此方法不存在时,模块构建式中的此代码就不会使用$this->setTemplateVersion(1)。模块构建式中的PHP错误将会妨碍Gallery API的版本检查。

完成了,使用如下内容做结束:

}
?>

整个module.inc代码可在此找到

模块的安装和激活

祝贺你,你已经编写完成了第一个G2模块!但目前你的模块还无法实际使用。如果不启用功能的话,就没有任何用处;所以,如果没有问题的话,你可以登入站点管理界面,点击插件(Plugins),下拉到额外数据(Extra Data)部分,然后安装并激活(在此还可以进行禁用和卸载)你的模块。很有意思,是不?

你刚刚创建完成了一个完全兼容且完美的G2模块。你会发现将来所制作的模块结构都是如此。好吧,是时候鼓励一下自己了,接下来的部分将教会你创建使用模板引擎的模块。

显示静态页面的模块

前言

现在你知道如何创建一个G2模块了,那么就让我们更深一步,创建使用模板引擎的模块以显示静态页面。

模块结构

首先创建一个modules/tutorial2目录。我们将从之前的模块继续。将旧的module.inc复制到新目录中,但请确保将tutorial1的所有实例修改为tutorial2Tutorial1修改为Tutorial2

另外,创建如下的文件和目录,目前这些文件都可以为空。

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

module.inc

我们不需要对module.inc做任何修改。MyPage.inc文件存在就允许G2使用它。继续并打开MyPage.inc文件。

MyPage.inc

在G2中是无法直接访问模板的。你必须使用一个"视图(view)",它将会准备所有必须的数据然后载入模板。MyPage.inc就是这样一种视图。

现在开始粘贴一般的G2样板文件。

<?php
/*
* Gallery – 基于web的相片相册查看器和编辑器
 * Copyright (C) 2000-2006 Bharat Mediratta
 *
 * 该程序为免费的,你可以对其做修改
 * 受GNU General Public License条款约束
 * 由Free Software Foundation发布;许可的第二版,或者说是
 * 以后的版本。
 *
 * 我们希望该应用程序能有用处,但
 * 不打包票;也不能保证其
 * 适销性或针对特殊目的的适用性。更多信息请参见GNU
 * General Public License。
 *
 * 在获取此程序的同时,你应当也收到了
* GNU General Public License;如果没有的话,请联系Free Software
 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
 */

填入其他标准数据。

/**
 * 该视图显示一个静态页面。
 *
 * @package Tutorial2
 * @subpackage UserInterface
 * @author Your Name <you@email.com>
 * @version $Revision$ $Date: 2006/01/05 07:00:00 $
 */

你应该对module.inc的结构不陌生吧,那你就应该知道接下来要做的了。我们希望使用你自己的类别对GalleryView类别进扩展。

class MyPageView extends GalleryView {

类别名称必须与你的*.inc文件名称相同,并以"View"结尾。现在,我们的模块还不需要做任何数据操作,我们只需要2个函数。其中主要的一个就是loadTemplate

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

loadTemplate函数中,我们告知G2在载入模板前所需做的所有事情。

对于我们的页面,将载入Gallery顶层相册,所以我们就可以显示有关它的一些信息了。

        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);应为return array($ret->wrap(__FILE__, __LINE__), null);

将这些呼叫的结构记录下来,这相当重要,因为在很多G2代码中都要重复使用它。另外注意我们已加载了根相册,但还没有对其做任何操作。现在将这些数据用于我们的模板。

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

我们用以显示页面的数据应当被给予$template->setVariable。无论何时模板数据被添加一个"实体",它都应当被转换为上面所示的数组。

现在让我们继续,来加载模板。

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

如果我们能走到这一步,那么所作的这些都成功了。所以,我们告知G2成功了,并载入合适的模板文件。

你是否边栏上的注意到back to ____导航链接了?让我们将此特点整入我们的模块中吧。要达到此目的,我们要创建另一个函数。

    /**
     * @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"改为你中意的明朝。最后,我们结束该类别以及PHP脚本。

}
?>

这么简单的一个任务看起来却用到了这么多代码,但这些代码可以在你今后的模块编写中反复使用的。你会发现,一旦掌握了基本模块的编码手段,就能轻松如意地编写更大更丰富的模块了。

现在是最后一个文件了,模板。

templates/MyPage.tpl

你应该能记得,loadTemplate()函数中的最后一个呼叫是模板的加载。G2使用Smarty模板引擎,这能提供很棒的代码与设计间的分离。 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$
 * 如果你想对此文件进行自定义的话,请勿直接编辑它,因为在将来升级时
 * 会将其覆盖掉。请将其复制到一个名为"local"的新建文件夹中再进行编辑
 * Gallery会首先查找此文件,如果存在的话就会先使用它。
 *}
<div class="gbBlock gcBackground1">
  <h2> {g->text text="Look, it's my first page! And it's got a title."} </h2>
</div>

这将在顶部创建美观的breadcrumb导航。注意G2系统呼叫在模板中的使用方式。所有Smarty呼叫都被包含在大括号内,有时会产生有趣的结果(当然还有可怕的错误),如果你尝试使用JavaScript,CSS或其他HTML相关使用大括号的古怪玩意的话。如果你确实想这么做的话,请将你的代码包括进{literal}..{/literal}标签中以告知Smarty你不想其被翻译。

另外使用{g->text text="在此输入你的文本"}来输出文本也是个好作法,但这不是必须的。就个人而言,我建议你不这么做,因为这将有可能会使你的模块被翻译成其他语言。

现在来填写模板的剩余部分。

<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>

我希望此模板足以进行自我解释。正如前面提到的,大部分可以使用HTML解决的问题同样可以使用模板引擎来完成。慢慢把玩此模板,直到达到你满意的效果。该文件最高级的部分就是以{if开头那行之上的一点点。这是Smarty使用的语法,从而能够根据情况显示输出。由于我们在模板数据中将"showAlbum"设定为true,因此你应当能在页面中看到根相册的标题。参见 Tpl相关参考中对Smarty功能的简述。

页面的访问

我们还没有在G2中对页面做任何连接,那么该如何进行访问呢?走运的是,G2(至少需要独立版本的G2)具有的一个标准方法可以访问模块和它们的视图:

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

你应当能看到新的静态页面被完美地包裹在G2外观主题和CSS之中。如果你得到了某个访问错误检查,你可以在'Site Admin / Plugins中激活该模块。

带有动作的页面

前言

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

模块结构

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

与数据库的协作

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.