使用 UserFrosting 的 OpenCart 错误重定向
Error redirects for OpenCart with UserFrosting
所以我一直致力于将 OpenCart 集成到 UserFrosting (http://www.userfrosting.com/)。基本上,我通过使用 .load
将页面注入到我自己的 html 页面上的 div
中,使所有管理仪表板页面加载到 UserFrosting 仪表板中。我快完成了,但还有最后一件工作没有留在 UF 仪表板中。
我将以目录/类别页面为例来展示我在做什么:
这是我的 html 类别文件,名称为 cata-categories.html
<!DOCTYPE html>
<html lang="en">
{% include 'components/head.html' %}
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
<body>
<div id="wrapper">
{% include 'components/nav-account.html' %}
<div id="page-wrapper">
{% include 'components/alerts.html' %}
<ol id="categories"></ol>
<script>
$( "#categories" ).load( "../solutions/admin/index.php?route=catalog/category" );
</script>
<br>
{% include 'components/footer.html' %}
</div>
</div></div>
</body>
</html>
这是通过 UserFrosting 的侧边栏访问的,代码如下 sidebar.html:
{% if checkAccess('uri_manage_groups') %}
<li>
<a href="{{site.uri.public}}/cata-categories/"><i class="fa fa-tags fa-fw"></i>Categories</a>
</li>
{% endif %}
页面通过 public/index.php 中的以下代码为 UserFrosting 呈现:
$app->get('/cata-categories/?', function () use ($app) {
$app->render('cata-categories.html', [
'page' => [
'author' => $app->site->author,
'title' => "Catagories",
'description' => "Catalogue Catagories.",
'alerts' => $app->alerts->getAndClearMessages()
]
]);
});
为了保持 OpenCart 页面上的所有链接都被点击,我将以下脚本放在每个主页面的底部 .tpl
(例如 category_list.tpl
):
<script>
$("#categories").on("click", "a", function (e) {
$("#categories").load($(this).attr("href"));
e.preventDefault();
});
</script>
然后为了在提交表单时将内容保持在同一页面上,我将控制器中的重定向(例如 category.php)更改为以下内容:
$this->response->redirect('../../portal/cata-categories');
一切正常,现在唯一的问题是表单提交或过滤结果出错。例如,如果有人试图添加一个新类别但没有填写任何信息并单击保存,它会重定向到 /admin/index.php?route=catalog/category/add
但不在 UserFrosting 仪表板内。
我希望它保留在我的仪表板中,并且需要在正确的方向上推动控制器中的修改内容才能做到这一点,我假设某种 AJAX 强制它不会重新加载页面而只是显示错误。过滤器按钮也一样,它显然需要向 URL 添加过滤器,因此不会在仪表板中加载 - 需要一种无需刷新即可进行过滤的方法。
非常感谢有修改 OpenCart 经验的人提供的任何帮助,如果您需要有关我正在做的事情的更多信息,请随时询问。
OpenCart 的路线不是为 AJAX 请求构建的
UserFrosting 和 OpenCart 处理 POST
请求的方式似乎根本不一致。如果您查看 catalog/category/add
route 的代码(或者至少,我认为是这样,但该代码似乎没有任何代码内文档,因此很难确定),您将看到这个:
public function add() {
$this->language->load('catalog/category');
$this->document->setTitle($this->language->get('heading_title'));
$this->load->model('catalog/category');
if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validateForm()) {
$this->model_catalog_category->addCategory($this->request->post);
$this->session->data['success'] = $this->language->get('text_success');
$url = '';
if (isset($this->request->get['sort'])) {
$url .= '&sort=' . $this->request->get['sort'];
}
if (isset($this->request->get['order'])) {
$url .= '&order=' . $this->request->get['order'];
}
if (isset($this->request->get['page'])) {
$url .= '&page=' . $this->request->get['page'];
}
$this->response->redirect($this->url->link('catalog/category', 'token=' . $this->session->data['token'] . $url, 'SSL'));
}
$this->getForm();
}
那么这里发生了什么?看起来当你 POST 到 catalog/category/add
时,它开始生成一个文档(我猜这就是前三行所做的),然后 然后 它处理您的 POST 请求(我相信 $this->model_catalog_category->addCategory($this->request->post);
实际上添加了类别)。
然后,它重建 URL 以列出所有类别(我假设),并实际将响应重定向到该页面(仍在处理 POST 的服务器端代码中请注意)。这一切都很好,并且实际上是大多数老式(AJAX 之前)应用程序的工作方式,但 UF 的做法略有不同。
UserFrosting 的路线(大部分)是RESTful
在UF中,一个POST请求是RESTful,这意味着只有一个POST请求的任务是修改一个资源。因此,当您在 UserFrosting 表单中单击 "submit" 时,POST 请求将在后台由 AJAX 调度,并在那里进行处理(成功更新资源和 return正在处理 HTTP 200
成功代码,或由于某种原因失败并 return 正在处理错误代码)。如果此请求后页面需要刷新或重定向,客户端 (Javascript) 代码负责执行此操作。
推荐
我的建议是完全放弃 OpenCart 的控制器,并以 RESTful 模式重新实现它。因此,与其使用 OpenCart 的 add()
方法,不如使用以下方法:
formCategoryAdd
:生成添加类别的表单。这可能就像 OpenCart 的 getForm
method. This is basically the same type of thing that UserFrosting's formUserCreate
的包装器一样简单。
addCategory
:这实际上处理了POST添加类别的请求。同样,在这里您可能只需要调用 OpenCart 的 addCategory
和 validateForm
方法即可。唯一的区别是您不会在完成时重定向请求。相反,您将向消息流添加一条成功消息(如果它成功添加了类别),或者您将添加一条错误消息,然后添加 return 适当的错误代码(如果由于某种原因失败) .请参阅 UserFrosting 的 createUser
方法以获取其工作原理的示例。
然后,回到客户端,您需要一些 Javascript 来处理表单提交。您基本上可以从任何 UF 页面窃取它。假设您的表单名为 add-category
:
<script>
$(document).ready(function() {
// Process form
$("form[name='add-category']").formValidation({
framework: 'bootstrap',
// Feedback icons
icon: {
valid: 'fa fa-check',
invalid: 'fa fa-times',
validating: 'fa fa-refresh'
},
fields: { "" : ""}
}).on('success.form.fv', function(e) {
// Prevent double form submission
e.preventDefault();
// Get the form instance
var form = $(e.target);
// Serialize and post to the backend script in ajax mode
var serializedData = form.serialize();
var url = form.attr('action');
$.ajax({
type: "POST",
url: url,
data: serializedData
}).done(function(data, statusText, jqXHR) {
// Forward to account home page on success
window.location.replace(site.uri.public);
}).fail(function(jqXHR) {
if ((typeof site !== "undefined") && site['debug'] == true) {
document.body.innerHTML = jqXHR.responseText;
} else {
console.log("Error (" + jqXHR.status + "): " + jqXHR.responseText );
// Display errors on failure
$('#userfrosting-alerts').flashAlerts().done(function() {
// Re-enable submit button
form.data('formValidation').disableSubmitButtons(false);
});
}
});
});
});
</script>
如果你想减少客户端代码重复,我把这个 Javascript 放到 dev
分支的一个单独的函数中:https://github.com/alexweissman/UserFrosting/blob/dev/public/js/userfrosting.js#L58-L113
所以我一直致力于将 OpenCart 集成到 UserFrosting (http://www.userfrosting.com/)。基本上,我通过使用 .load
将页面注入到我自己的 html 页面上的 div
中,使所有管理仪表板页面加载到 UserFrosting 仪表板中。我快完成了,但还有最后一件工作没有留在 UF 仪表板中。
我将以目录/类别页面为例来展示我在做什么:
这是我的 html 类别文件,名称为 cata-categories.html
<!DOCTYPE html>
<html lang="en">
{% include 'components/head.html' %}
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
<body>
<div id="wrapper">
{% include 'components/nav-account.html' %}
<div id="page-wrapper">
{% include 'components/alerts.html' %}
<ol id="categories"></ol>
<script>
$( "#categories" ).load( "../solutions/admin/index.php?route=catalog/category" );
</script>
<br>
{% include 'components/footer.html' %}
</div>
</div></div>
</body>
</html>
这是通过 UserFrosting 的侧边栏访问的,代码如下 sidebar.html:
{% if checkAccess('uri_manage_groups') %}
<li>
<a href="{{site.uri.public}}/cata-categories/"><i class="fa fa-tags fa-fw"></i>Categories</a>
</li>
{% endif %}
页面通过 public/index.php 中的以下代码为 UserFrosting 呈现:
$app->get('/cata-categories/?', function () use ($app) {
$app->render('cata-categories.html', [
'page' => [
'author' => $app->site->author,
'title' => "Catagories",
'description' => "Catalogue Catagories.",
'alerts' => $app->alerts->getAndClearMessages()
]
]);
});
为了保持 OpenCart 页面上的所有链接都被点击,我将以下脚本放在每个主页面的底部 .tpl
(例如 category_list.tpl
):
<script>
$("#categories").on("click", "a", function (e) {
$("#categories").load($(this).attr("href"));
e.preventDefault();
});
</script>
然后为了在提交表单时将内容保持在同一页面上,我将控制器中的重定向(例如 category.php)更改为以下内容:
$this->response->redirect('../../portal/cata-categories');
一切正常,现在唯一的问题是表单提交或过滤结果出错。例如,如果有人试图添加一个新类别但没有填写任何信息并单击保存,它会重定向到 /admin/index.php?route=catalog/category/add
但不在 UserFrosting 仪表板内。
我希望它保留在我的仪表板中,并且需要在正确的方向上推动控制器中的修改内容才能做到这一点,我假设某种 AJAX 强制它不会重新加载页面而只是显示错误。过滤器按钮也一样,它显然需要向 URL 添加过滤器,因此不会在仪表板中加载 - 需要一种无需刷新即可进行过滤的方法。
非常感谢有修改 OpenCart 经验的人提供的任何帮助,如果您需要有关我正在做的事情的更多信息,请随时询问。
OpenCart 的路线不是为 AJAX 请求构建的
UserFrosting 和 OpenCart 处理 POST
请求的方式似乎根本不一致。如果您查看 catalog/category/add
route 的代码(或者至少,我认为是这样,但该代码似乎没有任何代码内文档,因此很难确定),您将看到这个:
public function add() {
$this->language->load('catalog/category');
$this->document->setTitle($this->language->get('heading_title'));
$this->load->model('catalog/category');
if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validateForm()) {
$this->model_catalog_category->addCategory($this->request->post);
$this->session->data['success'] = $this->language->get('text_success');
$url = '';
if (isset($this->request->get['sort'])) {
$url .= '&sort=' . $this->request->get['sort'];
}
if (isset($this->request->get['order'])) {
$url .= '&order=' . $this->request->get['order'];
}
if (isset($this->request->get['page'])) {
$url .= '&page=' . $this->request->get['page'];
}
$this->response->redirect($this->url->link('catalog/category', 'token=' . $this->session->data['token'] . $url, 'SSL'));
}
$this->getForm();
}
那么这里发生了什么?看起来当你 POST 到 catalog/category/add
时,它开始生成一个文档(我猜这就是前三行所做的),然后 然后 它处理您的 POST 请求(我相信 $this->model_catalog_category->addCategory($this->request->post);
实际上添加了类别)。
然后,它重建 URL 以列出所有类别(我假设),并实际将响应重定向到该页面(仍在处理 POST 的服务器端代码中请注意)。这一切都很好,并且实际上是大多数老式(AJAX 之前)应用程序的工作方式,但 UF 的做法略有不同。
UserFrosting 的路线(大部分)是RESTful
在UF中,一个POST请求是RESTful,这意味着只有一个POST请求的任务是修改一个资源。因此,当您在 UserFrosting 表单中单击 "submit" 时,POST 请求将在后台由 AJAX 调度,并在那里进行处理(成功更新资源和 return正在处理 HTTP 200
成功代码,或由于某种原因失败并 return 正在处理错误代码)。如果此请求后页面需要刷新或重定向,客户端 (Javascript) 代码负责执行此操作。
推荐
我的建议是完全放弃 OpenCart 的控制器,并以 RESTful 模式重新实现它。因此,与其使用 OpenCart 的 add()
方法,不如使用以下方法:
formCategoryAdd
:生成添加类别的表单。这可能就像 OpenCart 的getForm
method. This is basically the same type of thing that UserFrosting'sformUserCreate
的包装器一样简单。addCategory
:这实际上处理了POST添加类别的请求。同样,在这里您可能只需要调用 OpenCart 的addCategory
和validateForm
方法即可。唯一的区别是您不会在完成时重定向请求。相反,您将向消息流添加一条成功消息(如果它成功添加了类别),或者您将添加一条错误消息,然后添加 return 适当的错误代码(如果由于某种原因失败) .请参阅 UserFrosting 的createUser
方法以获取其工作原理的示例。
然后,回到客户端,您需要一些 Javascript 来处理表单提交。您基本上可以从任何 UF 页面窃取它。假设您的表单名为 add-category
:
<script>
$(document).ready(function() {
// Process form
$("form[name='add-category']").formValidation({
framework: 'bootstrap',
// Feedback icons
icon: {
valid: 'fa fa-check',
invalid: 'fa fa-times',
validating: 'fa fa-refresh'
},
fields: { "" : ""}
}).on('success.form.fv', function(e) {
// Prevent double form submission
e.preventDefault();
// Get the form instance
var form = $(e.target);
// Serialize and post to the backend script in ajax mode
var serializedData = form.serialize();
var url = form.attr('action');
$.ajax({
type: "POST",
url: url,
data: serializedData
}).done(function(data, statusText, jqXHR) {
// Forward to account home page on success
window.location.replace(site.uri.public);
}).fail(function(jqXHR) {
if ((typeof site !== "undefined") && site['debug'] == true) {
document.body.innerHTML = jqXHR.responseText;
} else {
console.log("Error (" + jqXHR.status + "): " + jqXHR.responseText );
// Display errors on failure
$('#userfrosting-alerts').flashAlerts().done(function() {
// Re-enable submit button
form.data('formValidation').disableSubmitButtons(false);
});
}
});
});
});
</script>
如果你想减少客户端代码重复,我把这个 Javascript 放到 dev
分支的一个单独的函数中:https://github.com/alexweissman/UserFrosting/blob/dev/public/js/userfrosting.js#L58-L113