opencart 业务逻辑核心controller

本文详细解析了Opencart框架中Controller类的核心功能,包括其业务逻辑的横向分离与纵向组织,介绍了Controller如何通过动态收集页面元素并按照模板进行渲染。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

近期拖鞋接手了一个opencart的二次开发项目,所以不可避免地要把opencart本身的业务逻辑看个清楚,这对于毫无php开发基础的拖鞋来说,无疑是个蛋疼而艰巨的任务。

于是,从自学php,到把opencart的主要业务逻辑看通看懂,前前后后花了近一个星期,其中一手度娘一手gedit的辛酸自不多说,末了觉得收益良多,经验不敢独享,当然也怕自己忘记,遂记于此处,分享如下:

1.概述

正如标题所述,opencart的业务逻辑核心是controller类,源码位置opencart/system/engine/controller.php。作为一个核心业务类,controller定义了opencart所有后台业务的基本特征,从动态收集页面元素,到按照模版渲染页面

在横向上,它实现了“收集”与“渲染”的业务分离,在纵向上,它采用了层层嵌套的业务组织,从而使整个页面响应流程有条不紊地进行,清晰易用。以下也将主要从这两个方向,解释controller的这种设计特征。

2.横向的业务分离

controller的横向业务分离特征主要体现在render()函数。

 <?php
    protected 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();				
    	}
    }
?>

从上面的代码可以看到,foreach循环完成了当前controller页面元素的动态收集,它通过遍历当前controller所属的children(其实就是一个controller数组,下文有述,此处暂表不提),并用getchild()返回每个child的执行结果,然后把这些执行结果放在一个名叫data的数组中,完成收集功能。
foreach之后,紧接一个if else,判断当前controller所需模板是否存在,不存在则输出错误信息,此处我们主要看判断存在的支路,它完成了读取模板,并按照模板渲染页面的功能。
首先是extract()这个函数,度娘可知它是个php预定义函数,作用是把数组元素从键值形式转化成变量形式后,把它们统统置于当前的符号表中,举例来说,就是把数组中的a=>b转成$a=b后抛出,从而能使后面的代码使用$a(可视作临时变量,局限于当前作用域)。
从代码可知,作者正是通过使用这个神奇的函数,从而轻松地把之前存放在data中的执行结果“解包”出来,供后面require进来的模板“使用”。值得一提的是,这种“使用”过程事实上是被动的,是需要纳入模板设计者考虑的,关于这点我们随便打开一个默认模板目录(catalog/view/theme/default/template)下的模板就可以大概了解到,从data提取出的这些变量值,事实上恰恰确定了模板中所有用php书写的动态部分,也正因如此,作者才能用这么简单的几句代码就完成了controller的渲染。
此外,还有一个地方需要注意,关于ob_start(),ob_get_contents()与ob_end_clean()。ob其实就是缓冲区,ob_start()打开缓冲区后,此后代码的所有输出将全部放在这个用户不可见的缓冲区中,直到ob_end_clean()的出现,关闭并清除缓冲区。作者在此处用缓冲区存放渲染结果,然后再用ob_get_contents()返回缓冲区的输出内容到controller的output中,目的就是令渲染过程完成在缓冲区中,方便放于一个变量里,封装返回渲染结果。这对于controller纵向的层层嵌套是有重要意义的,下面也将述及这一点。

3.纵向的业务组织

controller的纵向业务组织特征是render()getchild()的联合作用。
上文已说了render(),此处重点说getchild(),下面将先理清其具体实现:

<?php
	protected 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();					
		}		
	}
?>

上文提过,这个函数将返回一个controller的output,条件是它需要一个child参数和一个可缺省的数组参数。这个child可以把它看成是一个controller子类的文件路径,这从它能作为action的构造参数就可以看出。

关于action,在这里我们先转过头去看看它的代码实现,它是一个同样放在engine目录下的类,其意义就是把一个controller子类的文件路径(也可能不是文件路径,而是一个精确到需调用函数的‘函数路径’),解释封装成一个指明了类名和需调用函数等“动作”信息的对象。当然,action的需调用函数通常会缺省,也就是当传入的路径参数的确是一个纯粹的文件路径时,action的需调用函数会默认指定为一个名为index的函数,一个所有controller子类都“约定”会有的函数。

关于index函数,我们先不管它的具体实现,下文会有继续有相关展开,现在只需知道它是一个通知controller子类对象准备相关信息,然后进行渲染工作的函数即可(好吧,其实这就是它的全部意义了……)。

有了这个概念,我们就可以回头看getchild()了。很明显的,new Action之后的一堆东西其实就是调用了controller子类对象的index,通知其进行渲染工作,并返回结果。

说完getchild,下面就可以展开对controller纵向特征的分析了:

首先,要说明的一点是,判断一个过程是否是嵌套机制,拖鞋习惯于关注两点,一是任务的下派,二是结果的返回,只要理清这两点,就可以很容易判断过程是否存在嵌套。

而在controller中,任务下派的过程体现在调用render时,遍历controller对象所属的每个child,并用getchild通知每个child执行工作,又因为child实际上是controller子类的对象,这个对象实现了一个准备了相关资料并调用render的index函数,所以这种通知child执行的工作事实上是层层下派的,由此,任务下派过程成立。

结果返回的过程则体现在返回getchild后,所有返回结果都存放在data数组中,而data在render中被用extract“解包”后,与模板共同作用渲染页面,然后再存放在output中。在这里考虑上文任务下派的层次关系,可以假定这个调用render的对象实际上是个controller子类对象,它的渲染任务是上一级controller分派下来的,那么,这个render应该是在这个子类对象的index中被调用,而index则在上一级controller的getchild中被调用。于是,在执行完index后,上一级controller的getchild把下一级的controller子类对象的output作为返回,从而完成逐级返回,由此,结果返回过程成立。

4.总结

要了解opencart的业务逻辑,controller的具体实现是绕不开的一道坎,而要了解controller的具体实现,拖鞋觉得从上面两个角度分析是比较好懂的,至少算是一种把灵活但凌乱的php模块化清晰化的努力,因此,才有了这篇博文。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值