opencart 模塊開發詳解
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中所有的模塊實例排序,並不是模塊實例間排序!
這樣是不是來龍去脈都打通了! 再設計模塊就會很輕松了吧 。