譯PrestaShop開發者指南第四篇深入PrestaShop核心開發

x3d發表於2014-01-04

## 訪問資料庫

### 資料庫結構

PrestaShop的資料庫表預設帶有ps_的字首,字首在安裝時可以自定義。

所有表名都是小寫,以下劃線分割。當一個表表示要在兩個實體間建立連線時,表名中兩個實體的的名稱都要出現,比如ps_category_product表示將產品關聯到對應的分類。

幾點細節:
– 用id_lang欄位來儲存與一條記錄相關的語言
– 用id_shop欄位來儲存與一條記錄相關的店鋪
– 以_lang字尾結尾的表表示包含翻譯,如ps_product_lang表包含ps_product表的所有翻譯
– 以_shop字尾結尾的表表示連結到指定店鋪的記錄,如ps_category_shop表包含每個分類對應在哪個店鋪上

### ObjectModel 類

ObjectModel是一個AR型別的類,它的一個例項對應一條資料庫記錄。

當你繼承了這個類以後,首先要定義模型的基本資訊。

<pre class=”brush:php”>
/**
* Example from the CMS model (CMSCore)
*/
public static $definition = array(
`table` => `cms`,
`primary` => `id_cms`,
`multilang` => true,
`fields` => array(
`id_cms_category` => array(`type` => self::TYPE_INT, `validate` => `isUnsignedInt`),
`position` => array(`type` => self::TYPE_INT),
`active` => array(`type` => self::TYPE_BOOL),
// Lang fields
`meta_description` =>
array(`type` => self::TYPE_STRING, `lang` => true, `validate` => `isGenericName`, `size` => 255),
`meta_keywords` =>
array(`type` => self::TYPE_STRING, `lang` => true, `validate` => `isGenericName`, `size` => 255),
`meta_title` =>
array(`type` => self::TYPE_STRING, `lang` => true, `validate` => `isGenericName`, `required` => true, `size` => 128),
`link_rewrite` =>
array(`type` => self::TYPE_STRING, `lang` => true, `validate` => `isLinkRewrite`, `required` => true, `size` => 128),
`content` =>
array(`type` => self::TYPE_HTML, `lang` => true, `validate` => `isString`, `size` => 3999999999999),
),
);

`multilang` => true,
`multishop` => true,
`multilang_shop` => true,
</pre>

主要呼叫方法:

<table class=”confluenceTable tablesorter”><thead><tr class=”sortableHeader”><th style=”text-align: center;” class=”confluenceTh sortableHeader tablesorter-headerSortDown” data-column=”0″><div class=”tablesorter-header-inner”><span style=”color: rgb(0,0,0);”><strong>Method name and parameters</strong></span></div></th><th style=”text-align: center;” class=”confluenceTh sortableHeader” data-column=”1″><div class=”tablesorter-header-inner”><span style=”color: rgb(0,0,0);”><strong>Description</strong></span></div></th></tr></thead><tbody class=””><tr><td colspan=”1″ class=”confluenceTd”><p>__construct($id = NULL, $id_lang = NULL)</p></td><td colspan=”1″ class=”confluenceTd”><p>Build object.</p></td></tr><tr><td colspan=”1″ class=”confluenceTd”><p>add($autodate = true, $nullValues = false)</p></td><td colspan=”1″ class=”confluenceTd”><p>Save current object to database (add or update).</p></td></tr><tr><td colspan=”1″ class=”confluenceTd”>associateTo(integer|array $id_shops)</td><td colspan=”1″ class=”confluenceTd”><p>Associate an item to its context.</p></td></tr><tr><td colspan=”1″ class=”confluenceTd”><p>delete()</p></td><td colspan=”1″ class=”confluenceTd”><p>Delete current object from database.</p></td></tr><tr><td colspan=”1″ class=”confluenceTd”>deleteImage(mixed $force_delete = false)</td><td colspan=”1″ class=”confluenceTd”><p>Delete images associated with the object.</p></td></tr><tr><td colspan=”1″ class=”confluenceTd”><p>deleteSelection($selection)</p></td><td colspan=”1″ class=”confluenceTd”><p>Delete several objects from database.</p></td></tr><tr><td colspan=”1″ class=”confluenceTd”><p>getFields()</p></td><td colspan=”1″ class=”confluenceTd”><p>Prepare fields for ObjectModel class (add, update).</p></td></tr><tr><td colspan=”1″ class=”confluenceTd”><p>getValidationRules($className = _CLASS_)</p></td><td colspan=”1″ class=”confluenceTd”><p>Return object validation rules (field validity).</p></td></tr><tr><td colspan=”1″ class=”confluenceTd”><p>save($nullValues = false, $autodate = true)</p></td><td colspan=”1″ class=”confluenceTd”><p>Save current object to database (add or update).</p></td></tr><tr><td colspan=”1″ class=”confluenceTd”><p>toggleStatus()</p></td><td colspan=”1″ class=”confluenceTd”><p>Toggle object`s status in database.</p></td></tr><tr><td colspan=”1″ class=”confluenceTd”><p>update($nullValues = false)</p></td><td colspan=”1″ class=”confluenceTd”><p>Update current object to database.</p></td></tr><tr><td colspan=”1″ class=”confluenceTd”><p>validateFields($die = true, $errorReturn = false)</p></td><td colspan=”1″ class=”confluenceTd”><p>Check for field validity before database interaction.</p></td></tr></tbody></table>

### DBQuery類

DBQuery是是一個用於構造SQL 查詢語句的助手類。

<pre class=”brush: php”>
$sql = new DbQuery();
$sql->select(`*`);
$sql->from(`cms`, `c`);
$sql->innerJoin(`cms_lang`, `l`, `c.id_cms = l.id_cms AND l.id_lang = `.(int)$id_lang);
$sql->where(`c.active = 1`);
$sql->orderBy(`position`);
return Db::getInstance()->executeS($sql
</pre>

譯註:這個類的方法很基本,跟國產的比差了一截,但一般的應用夠了。

## 路由分發

路由分發是v1.5引入的一項特性。

如下,當未啟用Url重寫時,

<pre>
http://myprestashop.com/index.php?controller=category&id_category=3&id_lang=1
http://myprestashop.com/index.php?controller=product&id_product=1&id_lang=2
</pre>

啟用重寫後:

<pre>
http://myprestashop.com/en/3-music-ipods
http://myprestashop.com/fr/1-ipod-nano.html
</pre>

路由分發器使用三個抽象類: Controller, FrontController 及d AdminController (後兩個繼承自第一個)。

可以通過過載loadRoutes()方法來建立新的路由。在後臺介面的”Preferences”選單下訪問”SEO & URLs”頁面就可以改變控制器的URL。

## 控制器

MVC的模式在此跳過不談。

所有的控制器實際上都過載了Controller類,如AdminController, ModuleAdminController, FrontController, ModuleFrontController等。

### FrontController類

主要屬性列表:

<pre>
Property
Description
$template Template name for page content.
$css_files Array list of CSS files.
$js_files Array list of JavaScript files.
$errors Array of errors that have occurred.
$guestAllowed Whether a customer who has signed out can access the page.
$initialized Whether the init() function has been called.
$iso The ISO code of the currently selected language.
$n The number of items per page.
$orderBy The field used to sort.
$orderWay Whether to sort is ascending or descending (“ASC” or “DESC”).
$p The current page number.
$ajax If the ajax parameter is detected in request, set this flag to true.
</pre>

### 控制器內部函式執行順序

1. __contruct(): Sets all the controller`s member variables.
1. init(): Initializes the controller.
1. setMedia() or setMobileMedia(): Adds all JavaScript and CSS specifics to the page so that they can be combined, compressed and cached (see PrestaShop`s CCC tool, in the back-office “Performance” page, under the “Advanced preferences” menu).
1. postProcess(): Handles ajaxProcess.
1. initHeader(): Called before initContent().
1. initContent(): Initializes the content.
1. initFooter(): Called after initContent().
1. display() or displayAjax(): Displays the content.

### 系統已有的控制器

控制器都在/controllers目錄下,自己去看。

### 過載控制器

系統自帶的控制器都帶了一個Core的字尾,如

<pre>
檔案 /controllers/CategoryController.php
類名: CategoryControllerCore
</pre>

要過載該控制器的話,

<pre>
檔案: /override/controllers/front/CategoryController.php
類名: CategoryController
</pre>

## 檢視

使用的Smarty引擎,副檔名.tpl。

## Cookies

統一使用/classes/Cookie.php中的類進行Cookie的讀寫。

<pre class=”brush:php”>
$this->context->cookie->variable;
</pre>

前端使用者儲存的cookie:

<pre>
Token
Description
viewed The IDs of recently viewed products as a comma-separated list.
passwd The MD5 hash of the _COOKIE_KEY_ in config/settings.inc.php and the password the customer used to log in.
logged Whether the customer is logged in.
last_visited_category The ID of the last visited category of product listings.
id_wishlist The ID of the current wishlist displayed in the wishlist block.
id_lang The ID of the selected language.
id_guest The guest ID of the visitor when not logged in.
id_customer The customer ID of the visitor when logged in.
id_currency The ID of the selected currency.
id_connections The connection ID of the visitor`s current session.
id_cart The ID of the current cart displayed in the cart block.
email The email address that the customer used to log in.
date_add The date and time the cookie was created (in YYYY-MM-DD HH:MM:SS format).
customer_lastname The last name of the customer.
customer_firstname The first name of the customer.
checksum The Blowfish checksum used to determine whether the cookie has been modified by a third party.
The customer will be logged out and the cookie deleted if the checksum doesn`t match.
checkedTOS Whether the “Terms of service” checkbox has been ticked (1 if it has and 0 if it hasn`t)
ajax_blockcart_display Whether the cart block is “expanded” or “collapsed”.
</pre>

後臺使用者儲存的cookie:

Token
Description
date_add The date and time the cookie was created (in YYYY-MM-DD HH:MM:SS format).
id_lang The ID of the selected language.
id_employee The ID of the employee.
lastname The last name of the employee.
firstname The first name of the employee.
email The email address the employee used to log in.
profile The ID of the profile that determines which tabs the employee can access.
passwd The MD5 hash of the _COOKIE_KEY_ in config/settings.inc.php and the password the employee used to log in.
checksum The Blowfish checksum used to determine whether the cookie has been modified by a third party.
If the checksum doesn`t match, the customer will be logged out and the cookie is deleted .

## 鉤子

鉤子是將你的程式碼與一些特定PrestaShop事件進行關聯的機制。

主要的鉤子有:

<pre>
Hook name
Description
displayFooter
Displays the content in the page`s footer area.
displayHeader Displays the content in the page`s header area.
displayHome Displays the content in the page`s central area.
displayLeftColumn Displays the content in the page`s left column.
displayRightColumn Displays the content in the page`s right column.
displayTop Displays the content in the page`s top area.

</pre>

### 使用鉤子

在控制器中,

<pre class=”brush:php”>
$this->context->smarty->assign(`HOOK_LEFT_COLUMN`, Module::hookExec(`displayLeftColumn`));
</pre>

在模組中,

<pre class=”brush:php”>
public function hookDisplayNameOfHook($params)
{
// Your code.
}
</pre>

為了讓模組響應鉤子的呼叫,要在模組安裝程式碼中將鉤子註冊到PrestaShop中,

<pre class=”brush:php”>
public function install()
{
return parent::install() && $this->registerHook(`NameOfHook`);
}
</pre>

在檢視中呼叫鉤子,很容易,

<pre class=”brush:html”>
{hook h=`displayLeftColumn` mod=`blockcart`}
</pre>

### 建立自己的鉤子

就是像上面模組安裝程式碼中的一樣,你想註冊自己的鉤子到系統中,只要簡單的呼叫:

<pre class=”brush:php”>
$this->registerHook(`NameOfHook`);
</pre>

即可。他等同於:

<pre class=”brush:sql”>
INSERT INTO `ps_hook` (`name`, `title`, `description`) VALUES (`nameOfHook`, `The name of your hook`, `This is a custom hook!`);
</pre>


相關文章