opencart 源码解析

原文转载:https://blog.csdn.net/dabao1989/article/details/21223585

//访问index.php,安全过滤、加载配置文件、核心启动文件、函数库、类库
//new注册表
$registry = new Registry();
 
//$registry里保存的config是根据当前店店铺(`oc_store`)获取`store_id`,然后到`oc_setting`里取出该店的配置信息,跟配置文件config.php无关
$query = $db->query("SELECT * FROM " . DB_PREFIX . "setting WHERE store_id = '0' OR store_id = '" . (int)$config->get('config_store_id') . "' ORDER BY store_id ASC");
foreach ($query->rows as $setting) {
    if (!$setting['serialized']) {
        $config->set($setting['key'], $setting['value']);
    } else {
        $config->set($setting['key'], unserialize($setting['value']));
    }
}
 
 
 
//依次new核心类,压入$registry,最后几个类需要当前$registry作为参数,new之后再重新压入$registry
$registry->set('customer', new Customer($registry));
 
//new Front();加载前置Action
$controller = new Front($registry);
$controller->addPreAction(new Action('common/seo_url'));    
$controller->addPreAction(new Action('common/maintenance'));
    
//根据当前URL,加载指定Action,默认加载Action('common/home');
if (isset($request->get['route'])) {
    $action = new Action($request->get['route']);
} else {
    $action = new Action('common/home');
}
 
//new Action()所进行的操作,根据URL路由,判断是否是一个控制器文件,如果是,break
//保存此控制器文件路径、当前需要执行的方法、参数等,假如方法名为空则要执行的方法名保存为index
function __construct($route, $args = array()) {
        $path = '';
 
        $parts = explode('/', str_replace('../', '', (string)$route));
 
        foreach ($parts as $part) { 
                $path .= $part;
 
                if (is_dir(DIR_APPLICATION . 'controller/' . $path)) {
                        $path .= '/';
 
                        array_shift($parts);
 
                        continue;
                }
 
                if (is_file(DIR_APPLICATION . 'controller/' . str_replace(array('../', '..\\', '..'), '', $path) . '.php')) {
                        $this->file = DIR_APPLICATION . 'controller/' . str_replace(array('../', '..\\', '..'), '', $path) . '.php';
 
                        $this->class = 'Controller' . preg_replace('/[^a-zA-Z0-9]/', '', $path);
 
                        array_shift($parts);
 
                        break;
                }
        }
 
        if ($args) {
                $this->args = $args;
        }
 
        $method = array_shift($parts);
 
        if ($method) {
                $this->method = $method;
        } else {
                $this->method = 'index';//默认index
        }
}
 
//Front执行控制器, 先执行之前压入的前置控制器, 然后执行当前请求的控制器, 失败则执行控制器error/not_found
//前置控制器有seo_url,maintenance,后台应该可配置SEO,可能会根据SEO创建新的控制器并返回,覆盖,执行
//Front->dispatch()会调用$this->execute()执行控制器
//execute()内部通过调用is_callable()判断控制器方法是否可以调用,所以可以在子Controller中将index()定义为protected,防止直接调用
//当直接调用时child Controller中的protected方法时,将会转到error/not_found
$controller->dispatch($action, new Action('error/not_found'));
function dispatch($action, $error) {
        $this->error = $error;
 
        foreach ($this->pre_action as $pre_action) {
                $result = $this->execute($pre_action);
 
                if ($result) {
                        $action = $result;//重置
 
                        break;
                }
        }
 
        while ($action) {
                $action = $this->execute($action);
        }
}
function execute($action) {
        if (file_exists($action->getFile())) {
                require_once($action->getFile());
 
                $class = $action->getClass();
 
                $controller = new $class($this->registry);
 
                if (is_callable(array($controller, $action->getMethod()))) {
                        $action = call_user_func_array(array($controller, $action->getMethod()), $action->getArgs());
                } else {
                        $action = $this->error;//当不可用时,会调用$this->error
 
                        $this->error = '';
                }
        } else {
                $action = $this->error;
 
                $this->error = '';
        }
 
        return $action;
}
 
//假设执行的控制器是common/home, 没有指定方法, 则执行index()
class ControllerCommonHome extends Controller {
    public function index() {
        $this->document->setTitle($this->config->get('config_title'));
        $this->document->setDescription($this->config->get('config_meta_description'));
 
        $this->data['heading_title'] = $this->config->get('config_title');
        
        if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/common/home.tpl')) {
            $this->template = $this->config->get('config_template') . '/template/common/home.tpl';
        } else {
            $this->template = 'default/template/common/home.tpl';
        }
        
        $this->children = array(
            'common/column_left',
            'common/column_right',
            'common/content_top',
            'common/content_bottom',
            'common/footer',
            'common/header'
        );
                                        
        $this->response->setOutput($this->render());
    }
}
 
//Controller中的render()方法
//会判断children属性是否赋值,有的话会逐个new child Controller,child Controller仍可以$this->render(),但调用$this->render()必须设定$this->template
//$this->data数组存储的值可在模板中使用
//$this->data[basename[$child]]保存的是子模板,common/home.tpl可以通过调用echo $column_left、$column_right、$content_top、$content_bottom输出
//应注意$this->data数组中的键值不要和子模板名重复!
function render() {
        foreach ($this->children as $child) {
                $this->data[basename($child)] = $this->getChild($child);
        }
 
        if (file_exists(DIR_TEMPLATE . $this->template)) {
                extract($this->data);//模板中使用
 
        ob_start();
 
                require(DIR_TEMPLATE . $this->template);
 
                $this->output = ob_get_contents();
 
        ob_end_clean();
 
                return $this->output;
} else {
                trigger_error('Error: Could not load template ' . DIR_TEMPLATE . $this->template . '!');
                exit();             
}
}
 
//controller中的getChild()方法
//只有在child Controller中执行了$this->render(),父Controller在$this->data[basename($child)]才能捕获到子模板,否则捕获的是空字符串
//虽然child Controller中的index()被定义为protected, 但是可以被父Controller调用, 因为他们都继承自Controller
function getChild($child, $args = array()) {
        $action = new Action($child, $args);
 
        if (file_exists($action->getFile())) {
                require_once($action->getFile());
 
                $class = $action->getClass();
 
                $controller = new $class($this->registry);
 
                $controller->{$action->getMethod()}($action->getArgs());
 
                return $controller->output;
        } else {
                trigger_error('Error: Could not load controller ' . $child . '!');
                exit();                 
        }       
}
 
//在主Controlle中,this->render()返回的模板需要传送给$this->response->setOutput()才能输出
$this->response->setOutput($this->render());
 
//Controller中的语言包使用,$this->language保存在$registry中
$this->language->load('common/footer');
$this->data['text_information'] = $this->language->get('text_information');
$this->data['text_service'] = $this->language->get('text_service');
 
//Controller中session使用,$this->session保存在$registry中
$this->session->data[$key];
$this->session->data[$key] = 'hello';
 
//Controller中的$this->request数组
$this->get = $_GET;
$this->post = $_POST;
$this->request = $_REQUEST;
$this->cookie = $_COOKIE;
$this->files = $_FILES;
$this->server = $_SERVER;
$this->request->get['route'];//获取方式
 
//Controller中的$this->response使用
$this->response->setOutput($this->render());
$this->response->setOutput(json_encode($json));
$this->response->addHeader('Content-Type: application/xml');
 
//Controller中的$this->customer
$this->customer->isLogged();//判断登录状态
$this->customer->logout();//退出操作
$this->customer->login();//登录操作
$this->getId();//获取用户ID,存储在customer表中的customer_id
 
//Controller中的页面跳转,$url->link()用于生成控制器的链接,如下
$this->redirect($this->url->link('catalog/information', 'token=' . $this->session->data['token'] . $url, 'SSL'));
 
//Controller中的forward(),用于new 新的控制器,并返回
function forward($route, $args = array()) {
        return new Action($route, $args);
}
 
//Controller中的模型加载
$this->load->model('catalog/category');
$this->model_catalog_category;//使用格式
 
//cache使用(原始使用文件缓存)
$this->cache->get($key);
$this->cache->set($key, $value);
$this->cache->delete($key);
 
//js,css等静态文件加载,通过Document对象加载额外的JS,CSS链接,在common子模板中会自动输出
$registry->document;
$registry->document->addLink($href, $rel);
$registry->addStyle($href, $rel = 'stylesheet', $media = 'screen');
$registry->addScript($script);
 
//币种
 
 
//模型机制
//在index.php创建数据库连接,并保存在$registry,根据DB_DRIVER不同,调用system/database/下指定的数据库引擎
//拥有4个方法:query(),escape(),countAffected(),getLastId()
//当验证外部数据时要用escape()进行安全过滤
$db = new DB(DB_DRIVER, DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_DATABASE);
$registry->set('db', $db);
 
//数据表解析
//oc_setting 配置
//oc_url_alias 配合apache rewrite,进行商品及分类URL优化
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342