opencart 模块开发详解

xiekanxiyang » 2013年 7月 11日 10:17 pm

opencart 将页面分成若干模块, 每个模块可以有多个实例(可能这样说不是很恰当) 每个实例可以指定它出现在哪个页面 这样更好的实现了代码的可重用性,可以达到更好的页面布局的可调节性. Opencar内置了几个模块,但实际应用中我们经常要根据需要开发自己模块,现在我给大家介绍下opencart的模块开发的细节

开发步骤:
首先:模块代码也分前台,后台. 后台功能是模块的安装,编辑,模块实例参数的设置等,而前台代码相对简单些就是将内容调出来显示在指定位置.
OC
是MVC+L设计 所以我们加一个功能时候通常会有四个文件 也就是:控制器(C)、模型(M)、视图(V)和 语言文件(L)
今天我们讲的模块有点特殊它的数据是存放在setting表里的,这样所有的模块model用setting的model就可以了 不需要另外写了,
这样我们开发新的模块,有这3个文件就可以了 前后台都一样,文件分别是 C+V+L;
它们分别放在各自文件下的module文件夹里,如果开发的话找个oc内置模块的将这3个文件复制份简单的替换下,如果新加的字段加上就可以了 ,
就能制作个新的模块。前台同样也有3个文件复制小改下就ok!这样一个新的模块就完成了。

模块安装:
在OC后台
Extensions > Moules 是模块管理页,
打开这个页它会检索admin\controller\module的所有文件,提取文件名作为模块名称
所以在这文件夹中的所有文件他都会认为是一个模块.
然后在数据库的oc_extension表中查询type为module中的记录,其中code字段就是已安装的模块名称。
也就是说在文件夹里的文件是所有的模块, 如果同时存在于oc_extension中,就认为是已安装的模块。 如果没有安装点击
安装后模块名插入此表。

模块后台代码分析:
以account模块为例,控制器代码如下 我加了注释供大家参考

    <?php
class ControllerModuleAccount extends Controller {
private $error = array(); public function index() {
$this->language->load('module/account'); //导入语言文件 $this->document->setTitle($this->language->get('heading_title')); //将语言文件里的 heading_title 设为标题 $this->load->model('setting/setting'); //加载 setting model 因为模型的实例的参数是放到oc_setting表中的 if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) { //如果有POST数据 并且检测用户权限通过
$this->model_setting_setting->editSetting('account', $this->request->post); //将数据更新到oc_setting表 $this->session->data['success'] = $this->language->get('text_success'); $this->redirect($this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL'));//更新完成跳回模型管理页
} //以下内容为语言文件的内容赋值到相应变量
$this->data['heading_title'] = $this->language->get('heading_title'); $this->data['text_enabled'] = $this->language->get('text_enabled');
$this->data['text_disabled'] = $this->language->get('text_disabled');
$this->data['text_content_top'] = $this->language->get('text_content_top');
$this->data['text_content_bottom'] = $this->language->get('text_content_bottom');
$this->data['text_column_left'] = $this->language->get('text_column_left');
$this->data['text_column_right'] = $this->language->get('text_column_right'); $this->data['entry_layout'] = $this->language->get('entry_layout');
$this->data['entry_position'] = $this->language->get('entry_position');
$this->data['entry_status'] = $this->language->get('entry_status');
$this->data['entry_sort_order'] = $this->language->get('entry_sort_order'); $this->data['button_save'] = $this->language->get('button_save');
$this->data['button_cancel'] = $this->language->get('button_cancel');
$this->data['button_add_module'] = $this->language->get('button_add_module');
$this->data['button_remove'] = $this->language->get('button_remove'); if (isset($this->error['warning'])) {
$this->data['error_warning'] = $this->error['warning'];
} else {
$this->data['error_warning'] = '';
} $this->data['breadcrumbs'] = array(); //面包屑导航
$this->data['breadcrumbs'][] = array(
'text' => $this->language->get('text_home'),
'href' => $this->url->link('common/home', 'token=' . $this->session->data['token'], 'SSL'),
'separator' => false
); $this->data['breadcrumbs'][] = array(
'text' => $this->language->get('text_module'),
'href' => $this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL'),
'separator' => ' :: '
); $this->data['breadcrumbs'][] = array(
'text' => $this->language->get('heading_title'),
'href' => $this->url->link('module/account', 'token=' . $this->session->data['token'], 'SSL'),
'separator' => ' :: '
); //post提交链接
$this->data['action'] = $this->url->link('module/account', 'token=' . $this->session->data['token'], 'SSL');
//取消按键的链接
$this->data['cancel'] = $this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL'); $this->data['modules'] = array(); //获取模型的参数
if (isset($this->request->post['account_module'])) {
$this->data['modules'] = $this->request->post['account_module'];
} elseif ($this->config->get('account_module')) {
$this->data['modules'] = $this->config->get('account_module');
} $this->load->model('design/layout'); //获取布局
$this->data['layouts'] = $this->model_design_layout->getLayouts(); //导入模板文件
$this->template = 'module/account.tpl';
$this->children = array(
'common/header',
'common/footer'
); $this->response->setOutput($this->render());
} //检测用户权限
protected function validate() {
if (!$this->user->hasPermission('modify', 'module/account')) {
$this->error['warning'] = $this->language->get('error_permission');
} if (!$this->error) {
return true;
} else {
return false;
}
}
}
?>

图片是模块参数在setting表中的记录 其中value就是参数数组序列化后的字符串

语言文件和模板就很简单了 这里就不说了

前台代码也很简单只是查出数据显示出来 一看就明白 也就不说了

模块前台显示机制:
模块设置时候会有个位置(position)选项 也就是模块在你指定页中的位置 有四个选项:content Top 、content Bottom 、column Left 、column Right四个选项。这里你选择哪个选项就会在哪个位置调用。

四个选项对应会有四个文件(控制器)
在前台控制器中catalog\controller\common这个路径下的同名文件便是,这里就是调用的地方。拿content
Top为例所有位置为content Top的模块都在 content_top.php文件中调用。 你指定的布局页会调用这四个文件
,所以就会调用你设定的模块了

Content Top 核心内容我加了注释 代码如下:

    <?php
class ControllerCommonContentTop extends Controller {
protected function index() {
$this->load->model('design/layout');
$this->load->model('catalog/category');
$this->load->model('catalog/product');
$this->load->model('catalog/information'); if (isset($this->request->get['route'])) {
$route = (string)$this->request->get['route'];
} else {
$route = 'common/home';
} $layout_id = 0; if ($route == 'product/category' && isset($this->request->get['path'])) {
$path = explode('_', (string)$this->request->get['path']); $layout_id = $this->model_catalog_category->getCategoryLayoutId(end($path));
} if ($route == 'product/product' && isset($this->request->get['product_id'])) {
$layout_id = $this->model_catalog_product->getProductLayoutId($this->request->get['product_id']);
} if ($route == 'information/information' && isset($this->request->get['information_id'])) {
$layout_id = $this->model_catalog_information->getInformationLayoutId($this->request->get['information_id']);
} if (!$layout_id) {
$layout_id = $this->model_design_layout->getLayout($route);
} if (!$layout_id) {
$layout_id = $this->config->get('config_layout_id');
} $module_data = array(); //加载extension model
$this->load->model('setting/extension'); //读取所有安装的模块
$extensions = $this->model_setting_extension->getExtensions('module'); foreach ($extensions as $extension) {
//读出每个模块的参数配置 模块参数是放到setting表中的 setting表中所有的数据在初始化时候就全读到config类里了 所有这里不需要读数据库
$modules = $this->config->get($extension['code'] . '_module'); if ($modules) {
foreach ($modules as $module) {
//过滤掉不是content_top的模块
if ($module['layout_id'] == $layout_id && $module['position'] == 'content_top' && $module['status']) {
$module_data[] = array(
'code' => $extension['code'],
'setting' => $module,
'sort_order' => $module['sort_order']
);
}
}
}
} $sort_order = array(); foreach ($module_data as $key => $value) {
$sort_order[$key] = $value['sort_order'];
}
//排序 这里大家明白了吧 排序在在整个位置排序 所有模块按sort_order排序 并不是每个模块单独排序! 这里大家一定要主要不然就会出乱子了!
array_multisort($sort_order, SORT_ASC, $module_data); $this->data['modules'] = array(); //$module_data里现在放的就是 content_top里所有的模块了 循环调用他们的控制器 就是module里模块对应的控制器 $module['setting']作为参数传入
foreach ($module_data as $module) {
//module 返回的html代码
$module = $this->getChild('module/' . $module['code'], $module['setting']); if ($module) {
$this->data['modules'][] = $module;
}
} //加载content_top的模板 模板很代码非常简单 就是循环输出 $module 也就是模块返回的html代码
if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/common/content_top.tpl')) {
$this->template = $this->config->get('config_template') . '/template/common/content_top.tpl';
} else {
$this->template = 'default/template/common/content_top.tpl';
} $this->render();
}
}
?>

最后总结下 因为模块参数是放到setting表中的所以后台存的时候不需要设置模型 用setting的模型就可以了
前台setting数据会在OC初始化的时候就读入config类里边了 所以连加载setting模型都省了 。另外排序的有效范围是按位置来分的,
比如content Top中所有的模块实例排序,并不是模块实例间排序!

这样是不是来龙去脉都打通了! 再设计模块就会很轻松了吧 。

opencart 模块开发详解的更多相关文章

  1. STM32开发 -- 4G模块开发详解(转)

    STM32开发 -- 4G模块开发详解(1) STM32开发 -- 4G模块开发详解(2) STM32开发 -- 4G模块开发详解(3) STM32开发 -- 4G模块开发详解(4)

  2. Springboot分模块开发详解(1):建立父工程

    基础服务,见下: base是父工程,base-entity是实体层,base-dao是DAO层,base-service是业务层,base-controller是WEB控制器层,base-web是页面 ...

  3. Springboot分模块开发详解(2):建立子工程

    1.创建base-entity 选中base工程,右键创建一个新的maven工程 自动选择了base这个目录存放子工程 创建后,pom.xml修改成如下内容: <?xml version=&qu ...

  4. EasyPR--开发详解(6)SVM开发详解

    在前面的几篇文章中,我们介绍了EasyPR中车牌定位模块的相关内容.本文开始分析车牌定位模块后续步骤的车牌判断模块.车牌判断模块是EasyPR中的基于机器学习模型的一个模块,这个模型就是作者前文中从机 ...

  5. 基于H5的微信支付开发详解

    这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可 ...

  6. ****基于H5的微信支付开发详解[转]

    这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可 ...

  7. AngularJS模块的详解

    AngularJS模块的详解 在讲angularjs的模块之前,我们先介绍一下angular的一些知识点: AngularJS是纯客户端技术,完全用Javascript编写的.它使用的是网页开发的常规 ...

  8. Xamarin+Prism开发详解七:Plugin开发与打包测试

    有了上章[Xamarin+Prism开发详解六:DependencyService与IPlatformInitializer的关系]的基础,现在来理解Plugin开发就简单了. 本文实例代码地址:ht ...

  9. ***PHP基于H5的微信支付开发详解(CI框架)

    这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可 ...

随机推荐

  1. 客户端(C#)调用CXF搭建的webservice的出现一些问题记录

    最近把XFire框架搭建的一个webservice换成CXF框架.访问webservice的客户端是C#写的.客户端调用webservice,数据能在客户端得到.看起来显然是成功了. 但其中在VS中添 ...

  2. java中的信号量Semaphore

    Semaphore(信号量)充当了操作系统概念下的“信号量”.它提供了“临界区中可用资源信号量”的相同功能.以一个停车场运作为例.为了简单起见,假设停车场只有三个车位,一开始三个车位都是空的.这时如果 ...

  3. web版本控制

    说说你在web开发中是怎么进行版本管理的 在web开发中,我首先将系统框架搭建完成后,我会发布到服务器上,然后给小组成员进行分工,为他们划分各自的模块,他们每天早上上班时就从服务器上先将自己机器上面的 ...

  4. mysql 累加排序求名次

    自己做的一个小项目里需要用mysql计算一些信息. mysql中的 表如下(注:表中数据都是测试数据,随机生成的) mysql> select * from shake_log; +-----+ ...

  5. unity3d shader之Roberts,Sobel,Canny 三种边缘检测方法

    方法其实都差不多,就是用两个过滤器,分别处理两个分量 Sobel算子 先说Sobel算子 GX为水平过滤器,GY为垂直过滤器,垂直过滤器就是水平过滤器旋转90度.过滤器为3x3的矩阵,将与图像作平面卷 ...

  6. HDOJ(HDU) 2524 矩形A + B(推导公式、)

    Problem Description 给你一个高为n ,宽为m列的网格,计算出这个网格中有多少个矩形,下图为高为2,宽为4的网格. Input 第一行输入一个t, 表示有t组数据,然后每行输入n,m ...

  7. 正则表达式的先行断言(lookahead)和后行断言(lookbehind)

    正则表达式的先行断言和后行断言一共有4种形式: (?=pattern) 零宽正向先行断言(zero-width positive lookahead assertion) (?!pattern) 零宽 ...

  8. [JIT_APP]Android SQLite简介

    SQLite介绍 SQLite是一个非常流行的嵌入式数据库,它支持SQL语言,并且只利用很少的内存就有很好的性能.此外它还是开源的,任何人都可以使用它.许多开源项目(Mozilla, PHP, Pyt ...

  9. 390. Elimination Game

    正规解法直接跳到代码上面一点的部分就可以了.但我想记录下自己的思考和尝试过程,希望二刷能看到问题所在. 找规律的时候写了好多,虽然规律很简单. 只要随便写3以上的例子,就应该发现,相邻的2个最后结果是 ...

  10. JDK JRE JVM

    使用java很久,但是一直不清楚JDK,JRE,JVM直接的关系,今天特地梳理一下. JDK:Java Development ToolKit(Java开发工具包),JDK是整个JAVA的核心,包括J ...