我正在为Joomla开发自定义组件!3.x并希望在其中进行AJAX调用以检索一些数据。正确的做法是什么?
我正在为Joomla开发自定义组件!3.x并希望在其中进行AJAX调用以检索一些数据。正确的做法是什么?
Answers:
请注意,此答案已经存在数年了,尚未更新。如果您认为某些内容不再正确,请随时进行编辑/评论。
几乎没有真正官方的方式来处理此问题,它很大程度上取决于复杂性以及您想要依靠MVC模式进行工作的程度。
以下是一些可能的解决方案,它们应在Joomla 2.5和3.x中起作用。该代码不是为复制粘贴作业提供的,而是作为一般思路提供的。
在Joomla之前!3.2您需要使用以下示例的唯一内容是component
。在Joomla 3.2(适用于复杂度较低的任务)之后,您可以处理来自模块和插件的请求。
您的任务网址应如下所示:
index.php?option=com_similar&task=abc&format=raw
然后,您要创建将使用该视图的控制器(假设)Abc
,其中将包含文件view.raw.html(与普通视图文件相同)。
下面是生成原始HTML响应的代码:
/controller.php
public function abc()
{
// Set view
// Joomla 2.5
JRequest::setVar('view', 'Abc');
// (use JInput in 3.x)
$this->input->set('view', 'Abc');
parent::display();
}
/views/abc/view.raw.php
<?php
defined('_JEXEC') or die;
jimport('joomla.application.component.view');
class SimilarViewAbc extends JViewLegacy
{
function display($tpl = null)
{
parent::display($tpl);
}
}
/views/abc/tmpl/default.php
<?php
echo "Hello World from /views/abc/tmpl/default.php";
注意:这是我必须返回HTML时将使用的解决方案(它更干净并且遵循Joomla逻辑)。要返回简单的JSON数据,请参阅下文如何将所有内容放入控制器。
如果你让你的Ajax请求的子控制器,如:
index.php?option=com_similar&controller=abc&format=raw
(对于原始视图)的子控制器名称必须为abc.raw.php
。
这也意味着您将/可能有2个名为Abc的子控制器。
如果返回JSON,则可以使用format=json
和abc.json.php
。在Joomla 2.5中。我在使该选项正常工作时遇到了一些问题(以某种方式破坏了输出),所以我使用了raw。
如果您需要生成有效的JSON响应,请查看docs页面生成JSON输出
// We assume that the whatver you do was a success.
$response = array("success" => true);
// You can also return something like:
$response = array("success" => false, "error"=> "Could not find ...");
// Get the document object.
$document = JFactory::getDocument();
// Set the MIME type for JSON output.
$document->setMimeEncoding('application/json');
// Change the suggested filename.
JResponse::setHeader('Content-Disposition','attachment;filename="result.json"');
echo json_encode($response);
通常,您会将这段代码放在控制器中(您将调用一个模型,该模型将返回您编码的数据-一种非常常见的情况)。如果需要进一步介绍,则还可以创建一个JSON视图(view.json.php),与原始示例类似。
现在,Ajax请求正在运行,请不要关闭页面。参见下文。
不要忘记检查伪造的请求。JSession::checkToken()
在这里派上用场。阅读有关如何向表单添加CSRF反欺骗的文档
如果您没有在请求中发送语言名称,Joomla可能不会翻译您想要的语言字符串。
考虑以某种方式将lang参数添加到您的请求中(如&lang=de
)。
Joomla 3.2的新功能!-使您能够在不构建组件的情况下发出处理请求
Joomla!Ajax接口 -Joomla现在提供了一种轻巧的方式来处理插件或模块中的Ajax请求。您可能要使用Joomla!Ajax接口,如果您还没有组件,或者需要从已有的模块发出请求。
JRequest
?不推荐使用$this->input
我的v3.x版本吗?
JRequest
。谢谢
Valid JSON Response
节中提到了它。
对于这个非常好的问题,这是一个较晚的答案,但是我想为那些只需要简单方法通过AJAX调用获取其组件数据的用户添加此切入点解决方案。
在数天的谷歌搜索中发现了所有Joomla版本,第三者的可能性以及黑客攻击之后,这是我能想到的最简单的方法-反馈得到了大家的赞赏。
execute
向我现有的主控制器添加了功能调用/执行任务的URL:
www.mysite.com/index.php?option=com_example&task=ForAjax.mytaskname
修改后的主控制器\ com_example \ controller.php
class ExampleController extends JControllerLegacy {
public function display($cachable = false, $urlparams = false) {
$app = JFactory::getApplication();
$view = $app->input->getCmd('view', 'default');
$app->input->set('view', $view);
parent::display($cachable, $urlparams);
return $this;
}
public function execute()
{
// Not technically needed, but a DAMN good idea. See http://docs.joomla.org/How_to_add_CSRF_anti-spoofing_to_forms
// JSession::checkToken();
$task = JFactory::getApplication()->input->get('task');
try
{
parent::execute($task);
}
catch(Exception $e)
{
echo new JResponseJson($e);
}
}
}
新的Subcontroller \ com_example \ controllers \ forajax.php
require_once JPATH_COMPONENT.'/controller.php';
class ExampleControllerForAjax extends ExampleController
{
public function MyTaskName()
{
$app = JFactory::getApplication();
$data['myRequest'] =$_REQUEST;
$data['myFile'] =__FILE__;
$data['myLine'] ='Line '.__LINE__;
$app->enqueueMessage('This part was reached at line ' . __LINE__);
$app->enqueueMessage('Then this part was reached at line ' . __LINE__);
$app->enqueueMessage('Here was a small warning at line ' . __LINE__, 'warning');
$app->enqueueMessage('Here was a big warning at line ' . __LINE__, 'error');
$task_failed = false;
echo new JResponseJson($data, 'My main response message',$task_failed);
$app->close();
}
}
呈现的JSON输出
{
success: true,
message: "My main response message",
messages: {
message: [
"This part was reached at line 26",
"Then this part was reached at line 27"
],
warning: [
"Here was a small warning at line 28"
],
error: [
"Here was a big warning at line 29"
]
},
data: {
myRequest: {
option: "com_example",
task: "mytaskname",
Itemid: null
},
myFile: "C:\mysite\components\com_example\controllers\forajax.php",
myLine: "Line 24"
}
}
Valentin的回答很好,但是如果您需要做的就是将1或2个ajax调用添加到已构建的组件中,则它会过于复杂。完全不分离controller.raw.php
或分离view.raw.php
文件是很可能的。
拨打这个ajax电话
index.php?format=raw&option=com_example&controller=job&task=keep_alive&tokenhash=1
在子job
控制器中
public function keep_alive() {
$this->ajax_check();
//Do your processing and echo out whatever you want to return to the AJAX call
header('HTTP/1.1 202 Accepted', true, 202);
echo 'OK';
JFactory::getApplication()->close();
}
// Verifies jtoken and does a basic check that this is actually an AJAX call
private function ajax_check() {
if(!JSession::checkToken('GET') || !isset($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) !== 'xmlhttprequest') {
header('HTTP/1.1 403 Forbidden', true, 403);
JFactory::getApplication()->close();
}
}
瓦伦丁的答案很好。
我更喜欢一个用于处理编码和错误处理的json控制器,我创建了一个json基类:
class itrControllerJson extends JControllerLegacy {
/** @var array the response to the client */
protected $response = array();
public function addResponse($type, $message, $status=200) {
array_push($this->response, array(
'status' => $status,
'type' => $type,
'data' => $message
));
}
/**
* Outputs the response
* @return JControllerLegacy|void
*/
public function display() {
$response = array(
'status' => 200,
'type' => 'multiple',
'count' => count($this->response),
'messages' => $this->response
);
echo json_encode($response);
jexit();
}
}
该控制器由负责该工作的控制器类扩展,如下所示:
require_once __DIR__.'json.php';
class componentControllerAddress extends itrControllerJson {
public function get() {
try {
if (!JSession::checkToken()) {
throw new Exception(JText::_('JINVALID_TOKEN'), 500);
}
$app = JFactory::getApplication();
$id = $app->input->get('id', null, 'uint');
if (is_null($id)) {
throw new Exception('Invalid Parameter', 500);
}
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query->select('*');
$query->from('#__table');
$query->where('id = '.$db->quote($id));
$db->setQuery($query);
$response = $db->loadObject();
$this->addResponse('message', $response, 200);
} catch (Exception $e) {
$this->addResponse('error', $e->getMessage(), 500);
}
$this->display();
}
}
然后您这样调用请求:
index.php?option=com_component&task=address.get&format=json&id=1234&tokenhash=1
通过JSession :: getFormToken()生成令牌哈希。因此,完整的完整调用可能如下所示:
$link = JRoute::_('index.php?option=com_component&task=address.get&format=json&id=1234&'.JSession::getFormToken().'=1', false);
第二个参数设置为“ false”,因此我们可以在javascript调用中使用此参数而无需重新编写xml。
JResponseJson
类来处理呢?