今天,我们将介绍 opencart 2.x 中的控制器概念。随着 OpenCart 2.x 版本的发布,他们引入了框架更改,如果您在早期版本 OpenCart 1.x 中制作了任何自定义模块,则需要升级。在本教程中,我们将通过一个我们称之为留言簿的实际示例进行演示。
在我们继续本文之前,您可以将其视为我之前所写内容的后续内容。在那篇文章中,我解释了如何在 OpenCart 1.x 中制作自定义页面,如果您已经阅读了那篇文章,那么您今天可以快速跳过大部分部分!
当然,今天要讨论的是 OpenCart 2.x,所以请确保您密切关注代码。
如果您想了解有关 OpenCart 框架模式和控制器的更多理论,您可以阅读该文章的几个初始部分。话虽如此,没有什么能阻止您立即关注本文,因为我不会跳过任何要点。
为什么要自定义控制器?
您可能首先要问的问题——为什么是自定义控制器?在我们开始之前,让我们快速了解一下 OpenCart 中的控制器是什么。
在 OpenCart 的上下文中,控制器是框架中不可或缺的组件,直接处理路由过程并呈现 UI。在此过程中,它处理其他重要组件,如语言、模型和视图,以构建最终结果。
当您访问 OpenCart 中的任何页面时,OpenCart 框架会查找相应的控制器并将进一步的处理委托给它。由于本质上是模块化的,OpenCart 框架提供了几个控制器来处理逻辑分组的功能。
例如,帐户组包含处理登录、注册、配置文件和类似用例的控制器。同样, 结帐 组的控制器处理订单创建过程。
简而言之,当您想要创建一个不在 OpenCart 核心中的功能并且它需要一个新 URL(OpenCart 术语中的路由)时,您应该使用自定义控制器。它使您可以完全控制页面创建过程——您希望在自定义页面上显示哪些元素。
创建自定义控制器
今天,我们将实现一个基本的留言板功能来演示自定义控制器的概念。在此过程中,我们将在前端构建一个界面,允许来宾用户通过输入他们的姓名和消息来提交他们的反馈。
在继续之前,请确保您已经安装了 OpenCart 2.3.x。这几乎就是开始我们的留言簿功能的工作了。
对于不熟悉 OpenCart 结构的人来说,寻找前端控制器的地方是catalog/controller. 它是根据它们提供的功能按组管理所有控制器的目录。
在我们的例子中,我们将创建一个名为 guestbook的单独组。继续创建一个目录catalog/controller/guestbook。在该目录中,创建一个entry.php包含以下内容的文件。它是一个控制器文件,用于处理我们留言簿功能的应用程序逻辑和提交逻辑。
<?php
class ControllerGuestbookEntry extends Controller {
private $error = array();
public function index() {
$this->load->language('guestbook/guestbook');
$this->document->setTitle($this->language->get('heading_title'));
if (($this->request->server['REQUEST_METHOD'] == 'post') && $this->validate()) {
$this->load->model('guestbook/guestbook');
$data['subject'] = sprintf('New guestbook entry submitted by %s', $this->request->post['guest_name']);
$data['message'] = $this->request->post['guest_message'];
$this->model_guestbook_guestbook->processGuestbookEntry($data);
$this->session->data['success'] = $this->language->get('text_success');
$this->response->redirect($this->url->link('guestbook/entry', '', true));
}
$data['success'] = '';
if (isset($this->session->data['success'])) {
$data['success'] = $this->session->data['success'];
unset($this->session->data['success']);
}
$data['breadcrumbs'] = array();
$data['breadcrumbs'][] = array(
'text' => $this->language->get('text_home'),
'href' => $this->url->link('common/home')
);
$data['breadcrumbs'][] = array(
'text' => $this->language->get('heading_title'),
'href' => $this->url->link('guestbook/entry', '', true)
);
$data['heading_title'] = $this->language->get('heading_title');
$data['entry_guest_name'] = $this->language->get('entry_guest_name');
$data['entry_guest_message'] = $this->language->get('entry_guest_message');
$data['entry_submit'] = $this->language->get('entry_submit');
if (isset($this->error['guest_name'])) {
$data['error_guest_name'] = $this->error['guest_name'];
} else {
$data['error_guest_name'] = '';
}
if (isset($this->error['guest_message'])) {
$data['error_guest_message'] = $this->error['guest_message'];
} else {
$data['error_guest_message'] = '';
}
$data['action'] = $this->url->link('guestbook/entry', '', true);
if (isset($this->request->post['guest_name'])) {
$data['guest_name'] = $this->request->post['guest_name'];
} else {
$data['guest_name'] = '';
}
if (isset($this->request->post['guest_message'])) {
$data['guest_message'] = $this->request->post['guest_message'];
} else {
$data['guest_message'] = '';
}
$data['column_left'] = $this->load->controller('common/column_left');
$data['column_right'] = $this->load->controller('common/column_right');
$data['content_top'] = $this->load->controller('common/content_top');
$data['content_bottom'] = $this->load->controller('common/content_bottom');
$data['footer'] = $this->load->controller('common/footer');
$data['header'] = $this->load->controller('common/header');
$this->response->setOutput($this->load->view('guestbook/entry', $data));
}
protected function validate() {
if (utf8_strlen(trim($this->request->post['guest_name'])) < 1) {
$this->error['guest_name'] = $this->language->get('error_guest_name');
}
if (utf8_strlen(trim($this->request->post['guest_message'])) < 1) {
$this->error['guest_message'] = $this->language->get('error_guest_message');
}
return !$this->error;
}
}
根据 OpenCart 命名约定,类名以 Controller关键字开头,后跟目录名,Guestbook在我们的例子中,就是类文件所在的目录。此外,Entry在我们的例子中,类文件的名称附加在末尾。
每个控制器类都提供了一个事实上的index方法来处理控制器的大部分逻辑。接下来,我们将浏览index方法中的代码,我们还将根据需要创建其他文件。
大多数情况下,我们将从包含特定组的语言文件开始。这是 OpenCart 在整个应用程序中管理静态语言标签的方式。当然,这使得多语言网站的实现变得轻而易举。
$this->load->language('guestbook/guestbook');
在继续之前,让我们创建相应的语言文件,以便我们的控制器可以找到它。创建一个 catalog/language/en-gb/guestbook/guestbook.php包含以下内容的文件。
<?php// Heading$_['heading_title']
= 'Guestbook'; // Entry$_['entry_guest_name']
= 'Your Name';$_['entry_guest_message']
= 'Message';$_['entry_submit']
= 'Submit';$_['text_success']
= 'Success: Your entry has been successfully submitted.'; // Error$_['error_guest_name']
= 'Please enter Your Name!';$_['error_guest_message']
= 'Please enter Message!';
如您所见,我们只是在语言数组中为标签分配了它们的值。
回到我们的控制器,接下来就是为我们的页面设置 html 标题标签。
$this->document->setTitle($this->language->get('heading_title'));
眼尖的用户会注意到,我们使用 heading_title了刚才创建的语言文件中定义的语言变量。
为了理解下一段代码,我们需要创建一个模型文件。所以一会儿,我将引导您创建模型文件,catalog/model/guestbook/guestbook.php其中包含以下内容。
<?php
class ModelGuestbookGuestbook extends Model {
public function processGuestbookEntry($data) {
// send email notification to store admin
$mail = new Mail();
$mail->protocol = $this->config->get('config_mail_protocol');
$mail->parameter = $this->config->get('config_mail_parameter');
$mail->smtp_hostname = $this->config->get('config_mail_smtp_hostname');
$mail->smtp_username = $this->config->get('config_mail_smtp_username');
$mail->smtp_password = html_entity_decode($this->config->get('config_mail_smtp_password'), ENT_QUOTES, 'UTF-8');
$mail->smtp_port = $this->config->get('config_mail_smtp_port');
$mail->smtp_timeout = $this->config->get('config_mail_smtp_timeout');
$mail->setTo($this->config->get('config_email'));
$mail->setFrom($this->config->get('config_email'));
$mail->setSender(html_entity_decode($this->config->get('config_name'), ENT_QUOTES, 'UTF-8'));
$mail->setSubject($data['subject']);
$mail->setText($data['message']);
$mail->send();
}
}
在 OpenCart 中,模型负责处理应用程序的业务逻辑。如果您希望实现任何涉及数据库的逻辑,这就是它应该进入的地方。
模型类的命名约定与控制器类的命名约定类似。为简单起见,我们实现了一种方法processGuestbookEntry,当用户提交留言簿条目时,通过电子邮件通知商店管理员。很简单吧?
让我们回到控制器,检查队列中的下一段代码。
if (($this->request->server['REQUEST_METHOD'] == 'POST') &&
$this->validate()) {
$this->load->model('guestbook/guestbook');
$data['subject'] = sprintf('New guestbook entry submitted by %s',
$this->request->post['guest_name']);
$data['message'] = $this->request->post['guest_message'];
$this->model_guestbook_guestbook->processGuestbookEntry($data);
$this->session->data['success'] = $this->language->get('text_success');
$this->response->redirect($this->url->link('guestbook/entry', '', true));}
它检查有效POST请求并通过调用该 validate方法对用户提交的数据进行基本验证。
该代码$this->load->model('guestbook/guestbook')用于加载我们刚才定义的模型。紧接着,我们$data根据用户输入准备数组并调用该 processGuestbookEntry方法,该方法会通知商店管理员有关留言簿条目的信息。最后,我们将用户重定向回留言簿入口页面。
在控制器中继续前进,以下代码段设置将在提交表单时显示的成功消息。
$data['success'] = '';
if (isset($this->session->data['success'])) {
$data['success'] = $this->session->data['success'];
unset($this->session->data['success']);}
之后,有一个片段用于为页面构建面包屑链接。
下一个片段是一个重要的片段,大部分时间你都会使用它来将信息从控制器方法传递到视图模板。
$data['heading_title'] = $this->language->get('heading_title');$data['entry_guest_name'] = $this->language->get('entry_guest_name');$data['entry_guest_message'] = $this->language->get('entry_guest_message');$data['entry_submit'] = $this->language->get('entry_submit');
与分配变量类似,OpenCart 初始化页面的常见元素(页眉、页脚等),如下面的片段所示。
$data['column_left'] = $this->load->controller('common/column_left');$data['column_right'] = $this->load->controller('common/column_right');$data['content_top'] = $this->load->controller('common/content_top');$data['content_bottom'] = $this->load->controller('common/content_bottom');$data['footer'] = $this->load->controller('common/footer');$data['header'] = $this->load->controller('common/header');
最后,它调用视图模板来渲染实际页面!
$this->response->setOutput($this->load->view('guestbook/entry', $data));
当然,我们还没有构建视图模板。现在是这样做的最佳时机!继续并创建一个 catalog/view/theme/default/template/guestbook/entry.tpl包含以下内容的文件。
<?php echo $header; ?>
<div class="container">
<ul class="breadcrumb">
<?php foreach ($breadcrumbs as $breadcrumb) { ?>
<li><a href="<?php echo $breadcrumb['href']; ?>"><?php echo $breadcrumb['text']; ?></a></li>
<?php } ?>
</ul>
<?php if ($success) { ?>
<div class="alert alert-success"><i class="fa fa-check-circle"></i> <?php echo $success; ?></div>
<?php } ?>
<div class="row"><?php echo $column_left; ?>
<?php if ($column_left && $column_right) { ?>
<?php $class = 'col-sm-6'; ?>
<?php } elseif ($column_left || $column_right) { ?>
<?php $class = 'col-sm-9'; ?>
<?php } else { ?>
<?php $class = 'col-sm-12'; ?>
<?php } ?>
<div id="content" class="<?php echo $class; ?>"><?php echo $content_top; ?>
<h1><?php echo $heading_title; ?></h1>
<form action="<?php echo $action; ?>" method="post" enctype="multipart/form-data" class="form-horizontal">
<div class="form-group required">
<label class="col-sm-2 control-label" for="input-guest-name"><?php echo $entry_guest_name; ?></label>
<div class="col-sm-10">
<input type="text" value="<?php echo $guest_name; ?>" name="guest_name" placeholder="<?php echo $entry_guest_name; ?>" id="input-guest-name" class="form-control" size="10" />
<?php if ($error_guest_name) { ?>
<div class="text-danger"><?php echo $error_guest_name; ?></div>
<?php } ?>
</div>
</div>
<div class="form-group required">
<label class="col-sm-2 control-label" for="input-guest-message"><?php echo $entry_guest_message; ?></label>
<div class="col-sm-10">
<textarea name="guest_message" placeholder="<?php echo $entry_guest_message; ?>" id="input-guest-message" class="form-control"><?php echo $guest_message; ?></textarea>
<?php if ($error_guest_message) { ?>
<div class="text-danger"><?php echo $error_guest_message; ?></div>
<?php } ?>
</div>
</div>
<div class="form-group required">
<label class="col-sm-2"> </label>
<div class="col-sm-10">
<input type="submit" value="<?php echo $entry_submit; ?>" class="btn btn-primary" />
</div>
</div>
</form>
<?php echo $content_bottom; ?></div>
<?php echo $column_right; ?></div>
</div>
<?php echo $footer; ?>
这是我们的主视图模板文件,负责显示留言簿页面的内容。在这个文件中,我们刚刚使用了在控制器index方法中设置的变量。
重要的是要注意响应性是 Bootstrap 框架支持的最新版本的 OpenCart 内置的。除此之外,它是非常容易理解的常规 HTML 内容。
所以,就文件设置而言,就是这样。
我们现在一切就绪,但您将如何从前端访问它?
在前端,您可以通过附加路由查询字符串变量来访问留言簿页面,因此 URL 应该类似于http://your-opencart-store-url/index.php?route=guestbook/entry。
让我们了解 OpenCart 如何将任何 URL 映射到特定的控制器文件。路由变量的格式是{directory}/{filename}/{methodname}.
{directory}组件映射catalog/controller到.
{filename}映射到 . 下的控制器文件的名称catalog/controller/{directory}。
最后,它会查找指定的控制器方法({methodname}如果它在路由中指定),否则它会调用默认index方法。
这是最终结果的样子。
当然,您可以继续通过提交表单来测试它,您应该会收到一封电子邮件通知到您注册为商店管理员的电子邮件地址。
结论
在任何框架中,继续实现自己的自定义功能总是令人高兴的。这正是今天教程的主题,我们在其中扩展了 OpenCart 并通过构建一个非常简单但有用的留言板功能来开发自定义控制器。
在这个过程中,我们意识到这不仅仅是控制器的问题——几乎没有其他关键元素是不可避免的。所以我们最终也引入了这些:模型、语言和视图。
最后,很高兴看到我在文章开头承诺的工作用例。所以,这就是今天的内容,不要犹豫,留下您的疑问和评论。另外,如果您希望我在下一篇文章中提出任何特定主题,我很乐意听取您的意见!