Tôi đang phát triển một thành phần tùy chỉnh cho Joomla! 3.x và muốn thực hiện một cuộc gọi AJAX bên trong nó để lấy một số dữ liệu. Cách thích hợp để làm điều đó là gì?
XIN LƯU Ý R ANNG TRẢ LỜI NÀY đã vài năm tuổi và chưa được cập nhật. Hãy chỉnh sửa/bình luận nếu bạn nghĩ rằng một cái gì đó không còn chính xác.
Hầu như không có cách nào thực sự chính thức để giải quyết vấn đề này, nó phụ thuộc nhiều vào độ phức tạp và mức độ bạn muốn dựa vào mẫu MVC để thực hiện công việc.
Dưới đây là một số giải pháp khả thi những gì nên hoạt động trong Joomla 2.5 và 3.x. Mã này không được trình bày cho một công việc sao chép - dán mà là một ý tưởng chung.
Trước Joomla! 3.2 điều duy nhất bạn cần sử dụng các ví dụ dưới đây là component
. Sau Joomla 3.2 (đối với các tác vụ phức tạp thấp hơn), bạn có thể xử lý yêu cầu từ các mô-đun và plugin.
[~ # ~] url [~ # ~] của bạn cho tác vụ cần giống như thế này:
index.php?option=com_similar&task=abc&format=raw
Bạn hơn là tạo bộ điều khiển sẽ sử dụng chế độ xem, giả sử Abc
, sẽ chứa tệp view.raw.html (giống hệt với tệp xem bình thường).
Dưới đây bạn có mã để tạo phản hồi HTML thô:
/control.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();
}
/lượt xem/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);
}
}
/lượt xem/abc/tmpl/default.php
<?php
echo "Hello World from /views/abc/tmpl/default.php";
Lưu ý: Đây là giải pháp tôi sẽ sử dụng nếu tôi phải trả về HTML (nó sạch hơn và tuân theo logic Joomla). Để trả về dữ liệu JSON đơn giản, hãy xem bên dưới cách đặt mọi thứ vào bộ điều khiển.
Nếu bạn thực hiện yêu cầu Ajax của mình với một bộ điều khiển con , như:
index.php?option=com_similar&controller=abc&format=raw
Hơn tên của trình điều khiển con của bạn (đối với chế độ xem thô) cần phải là abc.raw.php
.
Điều này cũng có nghĩa là bạn sẽ/có thể có 2 người điều khiển phụ tên là Abc.
Nếu bạn trả về JSON, có thể có ý nghĩa khi sử dụng format=json
Và abc.json.php
. Trong Joomla 2.5. Tôi có một số vấn đề khiến tùy chọn này hoạt động (bằng cách nào đó đầu ra bị hỏng), vì vậy tôi đã sử dụng thô.
Nếu bạn cần tạo phản hồi JSON hợp lệ , hãy xem trang tài liệu Tạo đầu ra 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);
Bạn thường sẽ đặt mã này vào bộ điều khiển (bạn sẽ gọi một mô hình sẽ trả về dữ liệu bạn mã hóa - một kịch bản rất phổ biến). Nếu bạn cần đưa nó đi xa hơn, bạn cũng có thể tạo chế độ xem JSON (view.json.php), tương tự như ví dụ thô.
Bây giờ yêu cầu Ajax đang hoạt động, chưa đóng trang. Đọc dưới đây.
Đừng quên kiểm tra các giả mạo yêu cầu. JSession::checkToken()
có ích ở đây. Đọc tài liệu về Cách thêm CSRF chống giả mạo vào biểu mẫ
Có thể xảy ra là nếu bạn không gửi tên ngôn ngữ trong yêu cầu, Joomla sẽ không dịch các chuỗi ngôn ngữ bạn muốn.
Xem xét nối thêm bằng cách nào đó lang param vào yêu cầu của bạn (như &lang=de
).
Mới trong Joomla 3.2! - cho phép bạn thực hiện các yêu cầu xử lý mà không cần xây dựng một thành phần
Joomla! Ajax Interface - Joomla hiện cung cấp một cách nhẹ nhàng để xử lý yêu cầu Ajax trong một plugin hoặc mô-đun. Bạn có thể muốn sử dụng Joomla! Giao diện Ajax nếu bạn chưa có thành phần hoặc nếu bạn cần thực hiện các yêu cầu từ mô-đun mà bạn đã có.
Đây là một câu trả lời muộn cho câu hỏi được trả lời rất tốt này, nhưng tôi muốn thêm giải pháp cắt xén này cho những người chỉ cần một cách đơn giản để lấy dữ liệu của các thành phần của họ bằng một cuộc gọi AJAX.
Với tất cả các phiên bản Joomla, khả năng của bên thứ 3 và các bản hack mà tôi đã tìm thấy trong nhiều ngày làm việc, đây là cách tiếp cận đơn giản nhất tôi có thể đưa ra - và phản hồi được DEFINATELY đánh giá cao.
execute
vào bộ điều khiển chính hiện có của tôiRL để gọi/thực hiện tác vụ :
www.mysite.com/index.php?option=com_example&task=ForAjax.mytaskname
Bộ điều khiển chính đã sửa đổi\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);
}
}
}
Bộ điều khiển mới\com_example\controls\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();
}
}
Kết xuất JSON được kết xuất
{
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"
}
}
Câu trả lời của Valentin là tốt nhưng hơi phức tạp một chút nếu tất cả những gì bạn cần làm là thêm 1 hoặc 2 cuộc gọi ajax vào một thành phần đã được xây dựng. Hoàn toàn có thể thoát khỏi việc không tách rời controller.raw.php
hoặc là view.raw.php
các tập tin.
Để thực hiện cuộc gọi ajax này
index.php?format=raw&option=com_example&controller=job&task=keep_alive&tokenhash=1
Trong bộ điều khiển con 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();
}
}
Câu trả lời của Valentin là tốt.
Tôi thích một bộ điều khiển json xử lý mã hóa và xử lý lỗi cho việc này Tôi đã tạo một lớp cơ sở 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();
}
}
Bộ điều khiển này được mở rộng bởi lớp trình điều khiển thực hiện công việc, đại loại như thế này:
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();
}
}
và bạn gọi yêu cầu như thế này:
index.php?option=com_component&task=address.get&format=json&id=1234&tokenhash=1
Hàm băm token được tạo bởi JSession :: getFormToken (). Vì vậy, cuộc gọi hoàn chỉnh hoàn chỉnh có thể giống như thế này:
$link = JRoute::_('index.php?option=com_component&task=address.get&format=json&id=1234&'.JSession::getFormToken().'=1', false);
Tham số thứ hai được đặt thành "false" để chúng tôi có thể sử dụng tham số này trong các cuộc gọi javascript mà không cần viết lại xml.
Nếu bạn chắc chắn 100% không có plugin bên thrid nào thêm bất kỳ đầu ra Javascript nào, thì json_encode thuần hoạt động.
Nhưng ... ví dụ JomSocial thêm "" vào toàn bộ trang.
Vì vậy, ... một mẹo hữu ích, bọc json_encode bằng các thẻ và xử lý nó ở phía Javascript.
echo '@[email protected]' . json_encode(...) . '@[email protected]';
Bạn có thể truy cập bộ điều khiển trực tiếp bằng cách sử dụng tên bộ điều khiển trong tác vụ:
index.php?option=com_similar&task=controller.abc&format=raw
sẽ gọi: control.raw.php (trả về là raw)
index.php?option=com_similar&task=controller.abc
sẽ gọi: controller.php (return là html nếu bạn không sử dụng die;
)