作为一名程序员,了解您正在使用的系统的流程很重要,这不仅是为了能够在需要时进行更改,而且因为这样做可以使您信心倍增。
今天,我们将选择OpenCart并对其进行剖析,以了解调度过程的基础。 我们将从调度过程的全部内容开始,并且随着我们的前进,我们将从框架的不同部分探索代码片段。
我将为本文选择OpenCart的最新版本,但其流程在早期版本中或多或少都相似。
简而言之调度
在任何基于Web的应用程序中,调度过程都用于查找传入请求URL与框架中相应模块之间的映射。 当然,实现因框架而异,但基本概念保持不变。 因此,这是调度程序的一些职责:
- 从请求对象中获取适当的参数。
- 查找相应的模块和要调用的动作。
- 如果找到了相应的模块和动作,则分配过程结束。
- 如果找不到给定请求的模块,则将设置默认操作,并且分发过程结束。
让我们尝试使用OpenCart中的一个简单示例来理解这一点。 要从前端创建新用户,需要使用http://www.youropencartstore.com/index.php?route=account/register在网站上进行注册。 让我们总结一下OpenCart为呈现请求的页面而采取的步骤。
- 首先,它检查“ route”查询字符串变量的存在,否则它将“ common / home”设置为页面的默认“ route”。
- 在我们的例子中,它存在,因此它将设置必需的变量并触发调度过程。
- 在调度过程的开始,它将运行一些用于执行常见任务的“ preAction”操作。 我们将在本文的后面部分讨论“ preAction”内容。
- 最后,它将检查当前“ route”变量是否有可用的控制器文件,如果有,则将调用该文件来获取响应。
- 如果没有控制器文件可用于请求的“ route”变量,它将执行“ error / not_found”操作,该操作向用户显示“找不到页面”消息。
因此,这是OpenCart如何遍历请求的URL并返回响应的顶层视图。 在下一节中,我们将更深入地了解它是如何做到的。
顺其自然
继续并在OpenCart的文档根目录中打开index.php
文件。 该文件中发生了很多事情,但不要被淹没,因为大多数只是整个框架中使用的对象的设置。
让我们直接从该文件中提取我们感兴趣的片段。
// Front Controller
$controller = new Front($registry);
// Maintenance Mode
$controller->addPreAction(new Action('common/maintenance'));
// SEO URL's
$controller->addPreAction(new Action('common/seo_url'));
与大多数其他框架一样,OpenCart也依赖于前控制器模式,因此应用程序中的所有请求都有一个公共入口点。
首先,我们创建前端控制器的实例,并将其分配给$controller
变量。 紧接着,我们正在调用addPreAction
方法来添加几个动作。
现在,这带来了另一个话题:什么是“ preAction”? 简单来说,preAction是一个动作,它将在任何页面上的请求动作之前执行。 例如,当用户单击任何页面时,您要在返回实际响应之前检查站点是否处于维护模式。 在这种情况下,您可以使用preAction,以便将用户重定向到维护页面(如果处于打开状态)。
另外,我们还添加了common/seo_url
作为preAction,因为在启用SEO的网站上,我们希望在实际分派开始之前获取相应的路由变量。
让我们继续下一个重要的代码片段。
// Router
if (isset($request->get['route'])) {
$action = new Action($request->get['route']);
} else {
$action = new Action('common/home');
}
它检查“ route”查询字符串变量的存在,如果存在,我们将通过传递当前的“ route”值作为构造函数参数来创建Action
类的实例。 如果不存在,我们将对主页路由URI( common/home
执行相同的操作。
将$action
变量设置为适当的值后,我们继续下一个代码段。
// Dispatch
$controller->dispatch($action, new Action('error/not_found'));
最后,我们调用前端控制器类的dispatch
方法。 继续打开system/engine/front.php
并找到以下片段。
public 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);
}
}
这是所有魔术发生的方法! 首先,它执行前面讨论的所有“ preAction”。 此外,在while循环中,它将尝试执行我们当前的$action
,将其作为execute
方法的参数传递。
让我们遵循同一文件中execute
方法的定义。
private function execute($action) {
$result = $action->execute($this->registry);
if (is_object($result)) {
$action = $result;
} elseif ($result === false) {
$action = $this->error;
$this->error = '';
} else {
$action = false;
}
return $action;
}
在第一行,将execute
Action
类的execute
方法。 不要将其与Front控制器类的execute
方法混淆。 打开文件system/engine/action.php
,就在这里。
public function execute($registry) {
// Stop any magical methods being called
if (substr($this->method, 0, 2) == '__') {
return false;
}
if (is_file($this->file)) {
include_once($this->file);
$class = $this->class;
$controller = new $class($registry);
if (is_callable(array($controller, $this->method))) {
return call_user_func(array($controller, $this->method), $this->args);
} else {
return false;
}
} else {
return false;
}
}
这里要注意的重要一点是,当在index.php
实例化操作对象时, Action
类已经在构造函数中设置了必需的变量。 它设置了file
, class
和method
属性,这些属性将在execute
方法中使用。 为了使事情不那么复杂,我们将只讨论execute
方法,尽管我建议您遍历Action
类的构造函数。
回到Action
类的execute
方法,它检查与当前路由关联的文件( $this->file
)是否存在。 如果一切正常,它将包含该文件,并使用call_user_func
函数调用该控制器类的相应方法( $this->method
),并返回响应。
如果关联的文件不可用,它将返回false
。 现在,让我们回到Front控制器类的execute
方法中的代码段。 耐心点,我们快到了!
...
$result = $action->execute($this->registry);
if (is_object($result)) {
$action = $result;
} elseif ($result === false) {
$action = $this->error;
$this->error = '';
} else {
$action = false;
}
return $action;
...
一旦Action
类的execute方法完成了该过程,它将返回结果并将其分配给$result
变量。 现在,存在三种不同的可能性,其值存储在$result
。 让我们检查每个。
如果一切顺利,我们将在$result
变量中提供HTML输出,因此$action
变量将设置为false
并结束过程。 这是最后一种情况。
回想一下,如果在Action
类的execute
方法中找不到相应的控制器文件,则返回false
。 在这种情况下, $action
变量将设置为$this->error
(error / not_found Action
),并向用户显示“找不到页面”。
最后,如果我们发现$result
是对象本身,则将其设置为$action
变量。 是的,这很奇怪:为什么在应该为请求的页面返回HTML输出的情况下,控制器方法究竟会返回另一个Action
对象? 但这只是控制器将用户重定向到其他URL的方式之一。
让我们快速打开catalog/controller/common/maintenance.php
文件并查看其运行情况。 在index
方法中,如果满足某些条件,它将返回Action
对象。
…
if (($route != 'payment' && $route != 'api') && !$this->user->isLogged()) {
return new Action('common/maintenance/info');
}
…
因此,如您所见,它返回Action
对象以将用户重定向到common/maintenance/info
URL。 当然,前端控制器类的dispatch
方法中有一个代码可以处理此行为。 回忆一下该方法中的代码片段-我保证这是本教程的最后一个代码片段。
...
while ($action) {
$action = $this->execute($action);
}
...
因此,这是一个while循环,它将一直运行到找到$action
变量设置为false
为止! 更具体地说,当我们为用户提供有用的输出时,它将结束循环。
这就是旅程的终点。 我希望它不会像乍看起来那样复杂。
结论
今天,我们经历了OpenCart框架的重要方面-调度过程。 我们了解了调度的基础知识,并通过完整的流程来了解调度的工作原理。
如果您正在寻找其他OpenCart工具,实用程序,扩展等,以便可以在自己的项目中使用或用于自己的教育,请不要忘记查看我们在市场上提供的产品 。
如有任何疑问,请随时留下您的评论。 另外, Twitter是与我联系的另一种选择,我很快做出了回应。
翻译自: https://code.tutsplus.com/articles/how-dispatching-works-in-opencart--cms-21787