在OpenCart 2.1.xx中创建自定义插件:第一部分

作为开发人员,在任何框架中构建自定义内容总是令人兴奋,并且OpenCart插件也是如此。

在这个分为两部分的系列中,我将解释OpenCart中的自定义插件开发。 从新手开发人员的角度出发,我们将详细介绍OpenCart中的扩展开发。 我们还将创建一个小的自定义插件,以演示OpenCart插件结构的各个方面。

在第一部分中,我们将构建一个自定义插件,以显示商店前端中的最新产品,您将能够从后端本身配置产品数量。 这就是本文的目的-开发具有配置表单的后端插件。

我假设您已经设置了OpenCart的最新版本,在撰写本文时为2.1.0.2。 在继续开发实际的插件之前,我将在下一部分中向您介绍OpenCart的基本插件体系结构。

MVCL简而言之

OpenCart是使用最流行的Web开发模式之一(MVC模式)开发的,只有很小的变化,或者我会说这是附加的。 附加功能以语言组件的形式出现,使其在OpenCart领域中成为MVCL。 可能您已经听说过这种模式,但是为了初学者,我将快速总结一下该模式的全部含义。

MVC中的M代表模型,这是大多数业务逻辑所在的地方。 在OpenCart的上下文中,该模型与数据库抽象层进行交互,以完成运行商店所需的所有繁重工作。 在这个区域中,您大多数时候会成为开发人员。

接下来,V代表View,它代表应用程序的表示层。 顾名思义,它仅处理任何页面的表示逻辑,并且大部分时间从其他层接收输入并生成XHTML输出。 应用程序的业务逻辑应远离此层; 它只应该担心该怎么做,而不是该怎么做。

MVC中的C(控制器)位于所有事物的前面,处理每个请求并相应地对其进行处理。 这个区域包含大多数应用程序逻辑,范围从处理和验证用户输入到加载适当的模型和查看组件以准备页面输出。

最后,还有一个附加组件L代表语言。 它使设置多语言站点变得轻而易举。

因此,这是OpenCart架构的快速概览,当我们继续深入解释每个组件时,它将更有意义。

任何OpenCart插件的骨架

让我们快速浏览一下我们需要为定制后端插件实现的文件列表。

  • admin/language/english/module/recent_products.php :这是一个文件,其中包含在整个admin应用程序区域中使用的静态标签。
  • admin/controller/module/recent_products.php :这是一个控制器文件,其中包含我们模块的应用程序逻辑。
  • admin/view/template/module/recent_products.tpl :这是一个视图模板文件,包含XHTML代码。

在下一节中,我们将创建上面提到的每个文件,并进行详细说明。

按照约定,我们需要将自定义插件文件放在模块目录下。 在这种情况下,当我们开发后端插件时,将是admin下保存文件的目录。 当然,根据上面显示的OpenCart架构,文件分布在不同的目录或组件中。

为后端插件创建文件

在本节中,我们将开始创建模块文件。 首先,我们将创建一个具有以下内容的语言文件admin/language/english/module/recent_products.php 。 从OpenCart的角度来看,这是一个重要文件,因为OpenCart必须检测到您的插件。

<?php
// admin/language/english/module/recent_products.php
// Heading
$_['heading_title']    = 'Recent Products';

// Text
$_['text_module']      = 'Modules';
$_['text_success']     = 'Success: You have modified Recent Products module!';
$_['text_edit']        = 'Edit Recent Products Module';

// Entry
$_['entry_name']       = 'Module Name';
$_['entry_limit']      = 'Limit';
$_['entry_status']     = 'Status';

// Error
$_['error_permission'] = 'Warning: You do not have permission to modify Recent Products module!';
$_['error_name']       = 'Module Name must be between 3 and 64 characters!';

如您所见,我们正在为PHP数组分配静态标签。 稍后,当数组转换为PHP变量时,您将可以在视图模板文件中访问这些变量。

您可能还已经注意到,该文件是在英语目录下创建的,因为它是商店的默认语言。 当然,对于多语言站点,您需要确保也为其他语言创建它。 例如,应在admin/language/french/module/recent_products.php创建同一文件的法语版本。

接下来,我们将创建最重要的插件文件之一-控制器文件。 让我们继续创建具有以下内容的admin/controller/module/recent_products.php

<?php
// admin/controller/module/recent_products.php
class ControllerModuleRecentProducts extends Controller {
    private $error = array();

    public function index() {
        $this->load->language('module/recent_products');

        $this->document->setTitle($this->language->get('heading_title'));

        $this->load->model('extension/module');

        if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
            if (!isset($this->request->get['module_id'])) {
                $this->model_extension_module->addModule('recent_products', $this->request->post);
            } else {
                $this->model_extension_module->editModule($this->request->get['module_id'], $this->request->post);
            }

            $this->session->data['success'] = $this->language->get('text_success');

            $this->response->redirect($this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL'));
        }

        $data['heading_title'] = $this->language->get('heading_title');

        $data['text_edit'] = $this->language->get('text_edit');
        $data['text_enabled'] = $this->language->get('text_enabled');
        $data['text_disabled'] = $this->language->get('text_disabled');

        $data['entry_name'] = $this->language->get('entry_name');
        $data['entry_limit'] = $this->language->get('entry_limit');
        $data['entry_status'] = $this->language->get('entry_status');

        $data['button_save'] = $this->language->get('button_save');
        $data['button_cancel'] = $this->language->get('button_cancel');

        if (isset($this->error['warning'])) {
            $data['error_warning'] = $this->error['warning'];
        } else {
            $data['error_warning'] = '';
        }

        if (isset($this->error['name'])) {
            $data['error_name'] = $this->error['name'];
        } else {
            $data['error_name'] = '';
        }

        $data['breadcrumbs'] = array();

        $data['breadcrumbs'][] = array(
            'text' => $this->language->get('text_home'),
            'href' => $this->url->link('common/dashboard', 'token=' . $this->session->data['token'], 'SSL')
        );

        $data['breadcrumbs'][] = array(
            'text' => $this->language->get('text_module'),
            'href' => $this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL')
        );

        if (!isset($this->request->get['module_id'])) {
            $data['breadcrumbs'][] = array(
                'text' => $this->language->get('heading_title'),
                'href' => $this->url->link('module/recent_products', 'token=' . $this->session->data['token'], 'SSL')
            );
        } else {
            $data['breadcrumbs'][] = array(
                'text' => $this->language->get('heading_title'),
                'href' => $this->url->link('module/recent_products', 'token=' . $this->session->data['token'] . '&module_id=' . $this->request->get['module_id'], 'SSL')
            );
        }

        if (!isset($this->request->get['module_id'])) {
            $data['action'] = $this->url->link('module/recent_products', 'token=' . $this->session->data['token'], 'SSL');
        } else {
            $data['action'] = $this->url->link('module/recent_products', 'token=' . $this->session->data['token'] . '&module_id=' . $this->request->get['module_id'], 'SSL');
        }

        $data['cancel'] = $this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL');

        if (isset($this->request->get['module_id']) && ($this->request->server['REQUEST_METHOD'] != 'POST')) {
            $module_info = $this->model_extension_module->getModule($this->request->get['module_id']);
        }

        if (isset($this->request->post['name'])) {
            $data['name'] = $this->request->post['name'];
        } elseif (!empty($module_info)) {
            $data['name'] = $module_info['name'];
        } else {
            $data['name'] = '';
        }

        if (isset($this->request->post['limit'])) {
            $data['limit'] = $this->request->post['limit'];
        } elseif (!empty($module_info)) {
            $data['limit'] = $module_info['limit'];
        } else {
            $data['limit'] = 5;
        }

        if (isset($this->request->post['status'])) {
            $data['status'] = $this->request->post['status'];
        } elseif (!empty($module_info)) {
            $data['status'] = $module_info['status'];
        } else {
            $data['status'] = '';
        }

        $data['header'] = $this->load->controller('common/header');
        $data['column_left'] = $this->load->controller('common/column_left');
        $data['footer'] = $this->load->controller('common/footer');

        $this->response->setOutput($this->load->view('module/recent_products.tpl', $data));
    }

    protected function validate() {
        if (!$this->user->hasPermission('modify', 'module/recent_products')) {
            $this->error['warning'] = $this->language->get('error_permission');
        }

        if ((utf8_strlen($this->request->post['name']) < 3) || (utf8_strlen($this->request->post['name']) > 64)) {
            $this->error['name'] = $this->language->get('error_name');
        }

        return !$this->error;
    }
}

它为扩展基础Controller类的自定义插件定义了新类。 按照约定,类的名称应模仿放置文件的目录结构。 因此,根据驼峰式惯例,通过替换斜杠和下划线字符,将路径controller/module/recent_products.php转换为ControllerModuleRecentProducts

接下来,有一个事实上的index方法,当将插件加载到前端时便被调用。 因此,这是一个索引方法,用于定义插件的大多数应用程序逻辑。

在当前应用程序的上下文中,简写$this->load->language加载相应的语言文件。 在我们的情况下,它将加载前面部分中定义的语言文件。 语法非常简单-您只需传递以module/为前缀的插件名称。 可以通过$this->language->get方法访问语言变量。

接下来,它通过使用文档对象的setTitle方法设置页面标题。

继续,速记$this->load->model用于加载模块模型。 模型类提供了用于保存模块参数等的实用方法。

之后,有一个重要的代码段,如下所示,它检查是否为POST数据提交,并在这种情况下保存模块配置。

if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
    if (!isset($this->request->get['module_id'])) {
        $this->model_extension_module->addModule('recent_products', $this->request->post);
    } else {
        $this->model_extension_module->editModule($this->request->get['module_id'], $this->request->post);
    }

    $this->session->data['success'] = $this->language->get('text_success');
    $this->response->redirect($this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL'));
}

此外,我们为$data数组分配了诸如heading_titletext_edit类的语言标签,以便我们可以在视图模板文件中使用它们。

之后,有一个代码片段可为配置页面构建正确的面包屑链接。

$data['breadcrumbs'] = array();

$data['breadcrumbs'][] = array(
    'text' => $this->language->get('text_home'),
    'href' => $this->url->link('common/dashboard', 'token=' . $this->session->data['token'], 'SSL')
);

$data['breadcrumbs'][] = array(
    'text' => $this->language->get('text_module'),
    'href' => $this->url->link('extension/module', 'token=' . $this->session->data['token'], 'SSL')
);

if (!isset($this->request->get['module_id'])) {
    $data['breadcrumbs'][] = array(
        'text' => $this->language->get('heading_title'),
        'href' => $this->url->link('module/recent_products', 'token=' . $this->session->data['token'], 'SSL')
    );
} else {
    $data['breadcrumbs'][] = array(
        'text' => $this->language->get('heading_title'),
        'href' => $this->url->link('module/recent_products', 'token=' . $this->session->data['token'] . '&module_id=' . $this->request->get['module_id'], 'SSL')
    );
}

如果已经在早期配置了模块并且处于编辑模式,则以下代码片段将填充默认模块配置。

if (isset($this->request->get['module_id']) && ($this->request->server['REQUEST_METHOD'] != 'POST')) {
    $module_info = $this->model_extension_module->getModule($this->request->get['module_id']);
}

最后,我们正在加载常见的页面元素,例如页眉,页脚和左侧边栏。 同样,这是$this->load->view简写形式,它加载实际的视图文件recent_products.tpl并显示配置表单。

在控制器文件中要记住一些重要的注意事项。 您会看到很多调用,例如$this->load->ELEMENT ,其中ELEMENT可以是视图,模型或语言。 它加载了相应的视图,模型和语言组件。

今天这篇文章的下一个也是最后一个文件是视图模板文件admin/view/template/module/recent_products.tpl 。 继续创建它!

<!-- admin/view/template/module/recent_products.tpl -->
<?php echo $header; ?><?php echo $column_left; ?>
<div id="content">
  <div class="page-header">
    <div class="container-fluid">
      <div class="pull-right">
        <button type="submit" form="form-recent-products" data-toggle="tooltip" title="<?php echo $button_save; ?>" class="btn btn-primary"><i class="fa fa-save"></i></button>
        <a href="<?php echo $cancel; ?>" data-toggle="tooltip" title="<?php echo $button_cancel; ?>" class="btn btn-default"><i class="fa fa-reply"></i></a></div>
      <h1><?php echo $heading_title; ?></h1>
      <ul class="breadcrumb">
        <?php foreach ($breadcrumbs as $breadcrumb) { ?>
        <li><a href="<?php echo $breadcrumb['href']; ?>"><?php echo $breadcrumb['text']; ?></a></li>
        <?php } ?>
      </ul>
    </div>
  </div>
  <div class="container-fluid">
    <?php if ($error_warning) { ?>
    <div class="alert alert-danger"><i class="fa fa-exclamation-circle"></i> <?php echo $error_warning; ?>
      <button type="button" class="close" data-dismiss="alert">&times;</button>
    </div>
    <?php } ?>
    <div class="panel panel-default">
      <div class="panel-heading">
        <h3 class="panel-title"><i class="fa fa-pencil"></i> <?php echo $text_edit; ?></h3>
      </div>
      <div class="panel-body">
        <form action="<?php echo $action; ?>" method="post" enctype="multipart/form-data" id="form-recent-products" class="form-horizontal">
          <div class="form-group">
            <label class="col-sm-2 control-label" for="input-name"><?php echo $entry_name; ?></label>
            <div class="col-sm-10">
              <input type="text" name="name" value="<?php echo $name; ?>" placeholder="<?php echo $entry_name; ?>" id="input-name" class="form-control" />
              <?php if ($error_name) { ?>
              <div class="text-danger"><?php echo $error_name; ?></div>
              <?php } ?>
            </div>
          </div>
          <div class="form-group">
            <label class="col-sm-2 control-label" for="input-limit"><?php echo $entry_limit; ?></label>
            <div class="col-sm-10">
              <input type="text" name="limit" value="<?php echo $limit; ?>" placeholder="<?php echo $entry_limit; ?>" id="input-limit" class="form-control" />
            </div>
          </div>
          <div class="form-group">
            <label class="col-sm-2 control-label" for="input-status"><?php echo $entry_status; ?></label>
            <div class="col-sm-10">
              <select name="status" id="input-status" class="form-control">
                <?php if ($status) { ?>
                <option value="1" selected="selected"><?php echo $text_enabled; ?></option>
                <option value="0"><?php echo $text_disabled; ?></option>
                <?php } else { ?>
                <option value="1"><?php echo $text_enabled; ?></option>
                <option value="0" selected="selected"><?php echo $text_disabled; ?></option>
                <?php } ?>
              </select>
            </div>
          </div>
        </form>
      </div>
    </div>
  </div>
</div>
<?php echo $footer; ?>

眼睛敏锐的用户已经注意到,它只是在显示从控制器文件传递来的变量。 除此之外,它是用于显示配置表单的简单XHTML代码,并且最重要的是,它开箱即用。

因此,就我们的后端自定义插件而言,就文件设置而言。

启用插件

转到OpenCart的后端,然后导航到Extensions> Modules 。 您应该在列表中看到“ 最近的产品 ”。 单击+号以安装模块,如以下屏幕截图所示。

Back-End Listing

安装完成后,您会看到一个编辑图标。 单击该按钮以打开模块配置表。

Configuration Form

在配置表单中,您可以设置要在前端块中显示的最新产品的数量。 另外,不要忘记将状态字段设置为Enabled ! 保存该模块,它应该看起来像这样。

Replicated Module

该模块有一个新条目,名为近期产品>我的近期阻止插件 。 原因是您可以为不同的页面多次复制它!

因此,我们快完成了! 我们已经在OpenCart中制作了完整的后端自定义插件。 在下一部分中,我们将介绍它的前端副本,该前端在前端显示漂亮的产品块!

结论

今天,我们讨论了OpenCart中的自定义插件开发。 在这个由两部分组成的系列的第一部分中,我们经历了后端插件开发,并创建了一个可工作的自定义插件,该插件提供了配置表单。

如果您正在寻找其他OpenCart工具,实用程序,扩展等,可以在自己的项目中使用或用于自己的教育,请查看我们在市场上提供的产品

在下一部分中,我们将通过创建在前端显示产品清单的前端部分来完成插件。 如有任何疑问和反馈,请使用下面的评论供稿。

翻译自: https://code.tutsplus.com/tutorials/create-a-custom-plugin-in-opencart-21xx-part-one--cms-26155

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值