译 PrestaShop开发者指南 第四篇 深入PrestaShop核心开发

简介: ## 访问数据库 ### 数据库结构 PrestaShop的数据库表默认带有ps_的前缀,前缀在安装时可以自定义。 所有表名都是小写,以下划线分割。当一个表表示要在两个实体间建立连接时,表名中两个实体的的名称都要出现,比如ps_category_product表示将产品关联到对应的分类。

## 访问数据库

### 数据库结构

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>

目录
相关文章
|
1月前
|
弹性计算 Java 关系型数据库
ARM架构和避坑指南|开发者分享会
今天分享的内容来自阿里云倚天ECS高级架构师张先国的“ARM架构和避坑指南”。本文内容主要从ARM架构、C和Java如何避坑 、等方面详细讲解。
|
开发工具 数据安全/隐私保护 git
三行代码搭建一个全能书籍系统(wiki)
三行代码搭建一个全能书籍系统(wiki)
三行代码搭建一个全能书籍系统(wiki)
|
JavaScript 前端开发
为方便大家使用,汇总一下VueAdminWork免费开源系列框架各版本
为方便大家使用,汇总一下VueAdminWork免费开源系列框架各版本
为方便大家使用,汇总一下VueAdminWork免费开源系列框架各版本
|
存储 前端开发 算法
1024程序节|完全开源、编程原生体验、轻量化,不来试试吗
1024程序节|完全开源、编程原生体验、轻量化,不来试试吗
146 0
1024程序节|完全开源、编程原生体验、轻量化,不来试试吗
|
监控 前端开发 安全
一套开源通用后台管理系统【私活必备脚手架】
一套开源通用后台管理系统【私活必备脚手架】
546 0
一套开源通用后台管理系统【私活必备脚手架】
|
SQL 关系型数据库 Linux